OSDN Git Service

* config/mips/mips.md (load_call[sd]i): Redefine using :P. Add mode
[pf3gnuchains/gcc-fork.git] / gcc / config / ip2k / ip2k.c
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.
5
6    This file is part of GCC.
7
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.
12
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.
17
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.  */
22
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"
50
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)
56
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);
87
88 const struct attribute_spec ip2k_attribute_table[];
89
90
91 /* Initialize the GCC target structure.  */
92 #undef TARGET_ASM_ALIGNED_HI_OP
93 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
94
95 #undef TARGET_ASM_FUNCTION_PROLOGUE
96 #define TARGET_ASM_FUNCTION_PROLOGUE function_prologue
97
98 #undef TARGET_ASM_FUNCTION_EPILOGUE
99 #define TARGET_ASM_FUNCTION_EPILOGUE function_epilogue
100
101 #undef TARGET_ASM_UNIQUE_SECTION
102 #define TARGET_ASM_UNIQUE_SECTION unique_section
103
104 #undef TARGET_ASM_FUNCTION_RODATA_SECTION
105 #define TARGET_ASM_FUNCTION_RODATA_SECTION default_no_function_rodata_section
106
107 #undef TARGET_ATTRIBUTE_TABLE
108 #define TARGET_ATTRIBUTE_TABLE ip2k_attribute_table
109
110 #undef TARGET_RTX_COSTS
111 #define TARGET_RTX_COSTS ip2k_rtx_costs
112 #undef TARGET_ADDRESS_COST
113 #define TARGET_ADDRESS_COST ip2k_address_cost
114
115 #undef TARGET_MACHINE_DEPENDENT_REORG
116 #define TARGET_MACHINE_DEPENDENT_REORG ip2k_reorg
117
118 #undef TARGET_INIT_LIBFUNCS
119 #define TARGET_INIT_LIBFUNCS ip2k_init_libfuncs
120
121 #undef TARGET_RETURN_IN_MEMORY
122 #define TARGET_RETURN_IN_MEMORY ip2k_return_in_memory
123
124 #undef TARGET_SETUP_INCOMING_VARARGS
125 #define TARGET_SETUP_INCOMING_VARARGS ip2k_setup_incoming_varargs
126
127 struct gcc_target targetm = TARGET_INITIALIZER;
128
129 /* Prologue/Epilogue size in words.  */
130 static int prologue_size;
131 static int epilogue_size;
132
133 /* compare and test instructions for the IP2K are materialized by
134    the conditional branch that uses them.  This is because conditional
135    branches are skips over unconditional branches.  */
136 rtx ip2k_compare_operands[3];   /* Additional operands for condition code.  */
137 int ip2k_test_flag;             /* Indicates Z, WREG contain condition code
138                                    information.  */
139
140 /* Some ip2k patterns push a byte onto the stack and then access
141    SP-relative addresses. Since reload doesn't know about these
142    pushes, we must track them internally with a %< (push) or %> (pop)
143    indicator.  */
144 static int ip2k_stack_delta;
145
146 /* Track if or how far our ip2k reorganization pass has run.  */
147 int ip2k_reorg_in_progress = 0;
148 int ip2k_reorg_completed = 0;
149 int ip2k_reorg_split_dimode = 0;
150 int ip2k_reorg_split_simode = 0;
151 int ip2k_reorg_split_himode = 0;
152 int ip2k_reorg_split_qimode = 0;
153 int ip2k_reorg_merge_qimode = 0;
154
155 /* Set up local allocation order.  */
156
157 void
158 ip2k_init_local_alloc (int *rao)
159 {
160   static const int alloc_order[] = REG_ALLOC_ORDER;
161
162   memcpy (rao, alloc_order, sizeof (alloc_order));
163 }
164
165 /* Returns the number of bytes of arguments automatically
166    popped when returning from a subroutine call.
167    FUNDECL is the declaration node of the function (as a tree),
168    FUNTYPE is the data type of the function (as a tree),
169    or for a library call it is an identifier node for the subroutine name.
170    SIZE is the number of bytes of arguments passed on the stack.  */
171
172 int
173 ip2k_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size)
174 {
175   if (TREE_CODE (funtype) == IDENTIFIER_NODE)
176     return size;
177
178   if (TYPE_ARG_TYPES (funtype) == NULL_TREE
179       || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
180     return size;
181
182   return 0;
183 }
184
185 /* Return nonzero if FUNC is a naked function.  */
186
187 static int
188 ip2k_naked_function_p (tree func)
189 {
190   tree a;
191
192   if (TREE_CODE (func) != FUNCTION_DECL)
193     abort ();
194   
195   a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
196   return a != NULL_TREE;
197 }
198
199 /* Output function prologue.  */
200 void
201 function_prologue (FILE *file, HOST_WIDE_INT size)
202 {
203   int leaf_func_p;
204   int main_p;
205   int reg;
206   rtx operands[2];
207
208   prologue_size = epilogue_size = 0;
209
210   if (ip2k_naked_function_p (current_function_decl))
211     {
212       fprintf (file, "/* prologue: naked */\n");
213       return;
214     }
215
216   leaf_func_p = leaf_function_p ();
217   main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
218
219   /* For now, we compute all these facts about the function, but don't
220      take any action based on the information.  */
221
222   prologue_size = 0;
223   fprintf (file, "/* prologue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n",
224            size);
225   
226   /* Unless we're a leaf we need to save the return PC.  */
227
228   if (! leaf_func_p)
229     {
230       OUT_AS1 (push, calll);
231       OUT_AS1 (push, callh);
232       prologue_size += 4;
233     }
234   
235   /* We need to save the old FP and set the new FP pointing at the
236      stack location where the old one is saved.  Note that because of
237      post-decrement addressing, the SP is off-by-one after the
238      push, so we harvest the SP address BEFORE we push the MSBs of
239      the FP.  */
240   if (CHAIN_FRAMES)
241     {
242       OUT_AS1 (push, REG_FP+1); /* Save old LSBs.  */
243       OUT_AS2 (mov, w, spl);
244       OUT_AS2 (mov, REG_FP+1, w); /* SPL -> FPL  */
245
246       OUT_AS2 (mov, w, sph);    /* Freeze SP MSBs  */
247       OUT_AS1 (push, REG_FP);   /* Save old MSBs  */
248       OUT_AS2 (mov, REG_FP, w); /* SPH -> FPH  */
249       prologue_size += 12;
250     }
251
252   for (reg = (CHAIN_FRAMES) ? (REG_FP - 1) : (REG_FP + 1);
253        reg > 0; --reg)
254     {
255       if (regs_ever_live[reg] && ! call_used_regs[reg])
256         {
257           fprintf (file, "\t" AS1 (push,%s) "\n", reg_names[reg]);
258           prologue_size += 2;
259         }
260     }
261
262   if (size)
263     {
264       operands[0] = GEN_INT (size);
265
266       switch (size & 0xff)
267         {
268         case 0:
269           break;
270         case 1: 
271           OUT_AS1 (dec, spl);
272           prologue_size += 2;
273           break;
274         default:
275           OUT_AS2 (mov, w, %L0);
276           OUT_AS2 (sub, spl, w);
277           prologue_size += 4;
278         }
279
280       switch (size & 0xff00)
281         {
282         case 0:
283           break;
284         case 0x100:
285           OUT_AS1 (dec, sph);
286           prologue_size += 2;
287           break;
288         default:
289           if ((size & 0xff) != ((size >> 8) & 0xff))
290             OUT_AS2 (mov, w, %H0); /* Otherwise W has value we want.  */
291           OUT_AS2 (sub, sph, w);
292           prologue_size += 4;
293         }
294     }
295
296 /* XXX - change this to use the carry-propagating subtract trick.  */
297   if (flag_stack_check)
298     {
299       OUT_AS2 (mov, w, sph);
300       OUT_AS2 (cmp, w, #%%hi8data(_end));
301       OUT_AS1 (sc, );                   /* C == 0 -> hi8(edata) < sph  */
302       OUT_AS1 (page, 1f);
303       OUT_AS1 (jmp, 1f);
304       OUT_AS1 (sz, );                   /* Z == 1 -> look at low byte  */
305       OUT_AS1 (page,0f); 
306       OUT_AS1 (jmp,0f);                 /* sp < edata, so raise stack fault  */
307       OUT_AS2 (mov, w, spl);
308       OUT_AS2 (cmp, w, #%%lo8data(_end));
309       OUT_AS1 (sc,);                    /* C==1 ->  lo8(edata) >= spl  */
310       OUT_AS1 (page,1f);
311       OUT_AS1 (jmp,1f);
312       OUT_AS1 (0:,);
313       output_asm_insn ("push\t$ff", operands);
314       OUT_AS1 (system,);
315       OUT_AS1 (1:, );
316       prologue_size += 30;
317     }
318 }
319
320 /* Output function epilogue.  */
321 void
322 function_epilogue (FILE *file, HOST_WIDE_INT size)
323 {
324   int leaf_func_p;
325   int reg,savelimit;
326   rtx operands[2];              /* Dummy used by OUT_ASn  */
327   int args_locals_size = current_function_args_size;
328   int saved_regs_p = 0;
329   int need_ret = 1;
330
331   /* Use this opportunity to reset the reorg flags!  */
332   ip2k_reorg_in_progress = 0;
333   ip2k_reorg_completed = 0;
334   ip2k_reorg_split_dimode = 0;
335   ip2k_reorg_split_simode = 0;
336   ip2k_reorg_split_himode = 0;
337   ip2k_reorg_split_qimode = 0;
338   ip2k_reorg_merge_qimode = 0;
339
340   if (ip2k_naked_function_p (current_function_decl))
341     {
342       fprintf (file, "/* epilogue: naked */\n");
343       return;
344     }
345
346   leaf_func_p = leaf_function_p ();
347   epilogue_size = 0;
348   fprintf (file, "/* epilogue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n",
349            size);
350
351   savelimit = (CHAIN_FRAMES) ? REG_FP : (REG_FP + 2);
352   for (reg = 0; reg < savelimit; reg++)
353     if (regs_ever_live[reg] && ! call_used_regs[reg])
354       {
355         saved_regs_p = 1;
356         break;
357       }
358
359   if (size)
360     {
361       if (leaf_func_p && !CHAIN_FRAMES && !saved_regs_p
362           && current_function_pops_args)
363         args_locals_size = current_function_args_size + size;
364       else
365         {
366           operands[0] = GEN_INT (size);
367
368           switch (size & 0xff)
369             {
370             default:
371               OUT_AS2 (mov, w, %L0);
372               OUT_AS2 (add, spl, w);
373               epilogue_size += 4;
374               /* fall-through  */
375             case 0:
376               break;
377             case 1:
378               OUT_AS1 (inc, spl);
379               epilogue_size += 2;
380             }
381
382           switch (size & 0xff00)
383             {
384             default:
385               if ((size & 0xff) != ((size >> 8) & 0xff))
386                 OUT_AS2 (mov, w, %H0);
387               OUT_AS2 (add, sph, w);
388               epilogue_size += 4;
389               /* fall-through  */
390             case 0:
391               break;
392             case 0x100:
393               OUT_AS1 (inc, sph);
394               epilogue_size += 2;
395             }
396         }
397     }
398
399   for (reg = 0; reg < savelimit; reg++)
400     {
401       if (regs_ever_live[reg] && ! call_used_regs[reg])
402         {
403           fprintf (file, "\t" AS1 (pop,%s) "\n", reg_names[reg]);
404           prologue_size += 2;
405         }
406     }
407
408   if (CHAIN_FRAMES
409       && ! (current_function_pops_args
410             && current_function_args_size >= 2
411             && current_function_args_size < 0x100))
412     {
413       OUT_AS1 (pop, REG_FP);
414       OUT_AS1 (pop, REG_FP+1);
415       epilogue_size += 4;
416     }
417
418   if (! leaf_func_p)
419     {
420       if (current_function_pops_args
421           && current_function_args_size >= 2
422           && current_function_args_size < 0x100)
423         {
424           if (current_function_args_size == 2)
425             {
426               if (CHAIN_FRAMES)
427                 {
428                   OUT_AS1 (page, __fp_pop2_args_ret);
429                   OUT_AS1 (jmp, __fp_pop2_args_ret);
430                 }
431               else
432                 {
433                   OUT_AS1 (page, __pop2_args_ret);
434                   OUT_AS1 (jmp, __pop2_args_ret);
435                 }
436               epilogue_size += 4;
437             }
438           else
439             {
440               operands[0] = GEN_INT (current_function_args_size);
441               OUT_AS2 (mov, w, %L0);
442               if (CHAIN_FRAMES)
443                 {
444                   OUT_AS1 (page, __fp_pop_args_ret);
445                   OUT_AS1 (jmp, __fp_pop_args_ret);
446                 }
447               else
448                 {
449                   OUT_AS1 (page, __pop_args_ret);
450                   OUT_AS1 (jmp, __pop_args_ret);
451                 }
452               epilogue_size += 6;
453             }
454           need_ret = 0;
455         }
456       else
457         {
458           OUT_AS1 (pop, callh);
459           OUT_AS1 (pop, calll);
460           epilogue_size += 4;
461         }
462     }
463   else
464     {
465       if (current_function_pops_args
466           && args_locals_size >= 2
467           && args_locals_size < 0x100)
468         {
469           if (args_locals_size == 2)
470             {
471               if (CHAIN_FRAMES)
472                 {
473                   OUT_AS1 (page, __leaf_fp_pop2_args_ret);
474                   OUT_AS1 (jmp, __leaf_fp_pop2_args_ret);
475                   epilogue_size += 4;
476                   need_ret = 0;
477                 }
478             }
479           else
480             {
481               operands[0] = GEN_INT (args_locals_size);
482               if (CHAIN_FRAMES)
483                 {
484                   OUT_AS2 (mov, w, %L0);
485                   OUT_AS1 (page, __leaf_fp_pop_args_ret);
486                   OUT_AS1 (jmp, __leaf_fp_pop_args_ret);
487                   epilogue_size += 6;
488                   need_ret = 0;
489                 }
490             }
491         }
492     }
493   
494   if (current_function_pops_args && args_locals_size && need_ret)
495     {
496       operands[0] = GEN_INT (args_locals_size);
497
498       switch (args_locals_size & 0xff)
499         {
500         default:
501           OUT_AS2 (mov, w, %L0);
502           OUT_AS2 (add, spl, w);
503           epilogue_size += 4;
504           /* fall-through  */
505
506         case 0:
507           break;
508
509         case 1:
510           OUT_AS1 (inc, spl);
511           epilogue_size += 2;
512         }
513
514       switch (args_locals_size & 0xff00)
515         {
516         default:
517           if ((args_locals_size & 0xff) != ((args_locals_size >> 8) & 0xff))
518             OUT_AS2 (mov, w, %H0);
519           OUT_AS2 (add, sph, w);
520           epilogue_size += 4;
521           /* fall-through  */
522
523         case 0:
524           break;
525
526         case 0x100:
527           OUT_AS1 (inc, sph);
528           epilogue_size += 2;
529         }
530     }
531
532   if (need_ret)
533     {
534       OUT_AS1 (ret,);
535       epilogue_size += 2;
536     }
537   
538   fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
539 }
540 \f
541 /* Return the difference between the registers after the function
542    prologue.
543
544    Stack Frame grows down:
545
546         ARGUMENTS
547                 <------ AP ($102:$103)
548         RETURN PC (unless leaf function)
549         SAVEDFP (if needed)
550                 <------ FP [HARD_FRAME_POINTER] ($FD:$FE)
551         SAVED REGS
552                 <------ VFP [$100:$101]
553         STACK ALLOCATION
554                 <------ SP ($6:$7)  */
555 int
556 ip2k_init_elim_offset (int from, int to)
557 {
558   int leaf_func_p = leaf_function_p ();
559   int no_saved_pc = leaf_func_p
560                     || ip2k_naked_function_p (current_function_decl);
561   int offset;
562   int reg;
563   int reglimit;
564
565   if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
566     return get_frame_size () + 1;
567
568   if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
569     return (CHAIN_FRAMES ? 2 : 0) + (no_saved_pc ? 0 : 2);
570       
571   /* Count all the registers we had to preserve.  */
572
573   reglimit = CHAIN_FRAMES ? REG_FP : (REG_FP + 2);
574   for (offset = 0,reg = 0; reg < reglimit; ++reg)
575     {
576       if ((regs_ever_live[reg] && ! call_used_regs[reg]))
577         {
578           ++offset;
579         }
580     }
581
582   if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
583     return -offset;
584
585   if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
586     /* Add in the stack-local variables.  */
587     return offset + get_frame_size () + 1;
588
589   if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
590     /* Add stack-locals plus saved FP and PC.  */
591     return offset + get_frame_size () + 1
592            + (CHAIN_FRAMES ? 2 : 0) + (no_saved_pc ? 0 : 2);
593
594   abort ();                     /* Unanticipated elimination.  */
595 }
596
597 /* Return nonzero if X (an RTX) is a legitimate memory address on the target
598    machine for a memory operand of mode MODE.  */
599
600 int
601 legitimate_address_p (enum machine_mode mode, rtx x, int strict)
602 {
603   int off;
604
605   if (GET_CODE (x) == SUBREG)
606      x = SUBREG_REG (x);
607
608   switch (GET_CODE (x))
609     {
610     case REG:
611       /* IP allows indirection without offset - only okay if
612          we don't require access to multiple bytes.  */
613       if (REGNO (x) == REG_IP)
614         return (GET_MODE_SIZE (mode) == 1) ? 'R' : 0;
615
616       /* We can indirect through DP or SP register.  */
617       if (strict ? REG_OK_FOR_BASE_STRICT_P (x)
618                  : REG_OK_FOR_BASE_NOSTRICT_P (x))
619         return 'S';
620       break;
621
622     case PLUS:
623       /* Offsets from DP or SP are legal in the range 0..127  */
624       {
625         rtx op1, op2;
626
627         op1 = XEXP (x, 0);
628         op2 = XEXP (x, 1);
629
630         if (REG_P (op2) && ! REG_P (op1))
631           {
632             rtx tmp = op1;
633             op1 = op2;
634             op2 = tmp;
635           }
636
637         /* Don't let anything but R+I through..  */
638         if (! REG_P (op1)
639             || REG_P (op2)
640             || GET_CODE (op2) != CONST_INT)
641           return 0;
642               
643         switch (REGNO (op1))
644           {
645           case REG_DP:          /* only 0..127 displacement  */
646           case REG_SP:
647             off = 2 * GET_MODE_SIZE (mode);
648             if (! off)
649               off = 1;
650
651             if (INTVAL (op2) < 0 || INTVAL (op2) > (128 - off))
652               return 0;         /* Positive must be small enough that after
653                                    splitting all pieces are addressed.  */
654             return 'S';         /* Safe displacement.  */
655
656           case REG_IP:
657             if (GET_MODE_SIZE (mode) <= 1 && INTVAL (op2) == 0)
658               return (GET_MODE_SIZE (mode) == 1) ? 'R' : 0;
659             return 0;
660
661           case REG_AP:
662           case REG_FP:
663           case REG_VFP:
664           default:
665             if (strict || ! REG_OK_FOR_BASE_NOSTRICT_P (op1))
666               return 0;         /* Allow until reload.  */
667
668             return 'S';
669           }
670       }
671       break;
672
673     case CONST:
674     case SYMBOL_REF:
675          /* We always allow references to things in code space.  */
676       return is_regfile_address (x) ? 0 : 'C';
677
678     case LABEL_REF:
679       return 'L';
680
681     default:
682       return 0;
683     }
684
685   return 0;
686 }
687
688 /* Is ADDR mode dependent?  */
689 int
690 ip2k_mode_dependent_address (rtx addr)
691 {
692   switch (GET_CODE (addr))
693     {
694     case POST_INC:
695     case POST_DEC:
696     case PRE_INC:
697     case PRE_DEC:
698       return 1;
699
700     case REG:
701       return (REGNO (addr) == REG_IP); /* Can't do IP displaced addresses.  */
702
703     default:
704       return 0;                 /* Assume no dependency.  */
705     }
706 }
707
708 /* Attempts to replace X with a valid
709    memory address for an operand of mode MODE.  */
710
711 rtx
712 legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
713                     enum machine_mode mode ATTRIBUTE_UNUSED, rtx scratch)
714 {
715   rtx reg;
716
717   /* You might think that we could split up a symbolic address by
718      adding the HIGH 8 bits and doing a displacement off the dp.  But
719      because we only have 7 bits of offset, that doesn't actually
720      help.  So only constant displacements are likely to obtain an
721      advantage.  */
722       
723   if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0))
724       && GET_CODE (XEXP (x, 1)) == CONST_INT
725       && ! CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'K'))
726     {
727       int offset = INTVAL (XEXP (x, 1));
728
729       reg = scratch ? scratch : gen_reg_rtx (Pmode);
730
731       emit_insn (gen_rtx_SET (VOIDmode, reg,
732                               gen_rtx_PLUS (Pmode, XEXP (x, 0),
733                                             GEN_INT (offset & 0xffc0))));
734       x = gen_rtx_PLUS (Pmode, reg, GEN_INT (offset & 0x3f));
735     }
736
737   return x;                     /* We don't have any other tricks.  */
738 }
739 \f
740 /* Determine if X is a 'data' address or a code address.  All static
741    data and stack variables reside in data memory.  Only code is believed
742    to be in PRAM or FLASH.  */
743 int
744 is_regfile_address (rtx x)
745 {
746   while (1)
747     switch (GET_CODE (x))
748       {
749       case SYMBOL_REF:
750         return ! SYMBOL_REF_FUNCTION_P (x); /* Declared as function.  */
751       case CONST:
752       case PLUS:
753         x = XEXP (x, 0);
754         break;
755       case CONST_INT:
756       case REG:
757       case SUBREG:
758         return 1;
759       case LABEL_REF:
760         return 0;
761       default:
762         return 0;
763     }
764
765   return 0;
766 }
767
768 /* Output ADDR to FILE as address.  */
769
770 void
771 print_operand_address (FILE *file, rtx addr)
772 {
773   switch (GET_CODE (addr))
774     {
775     case SUBREG:
776       addr = alter_subreg (&addr);
777       /* fall-through  */
778
779     case REG:
780       fprintf (file, "(%s)",
781                REGNO (addr) == REG_DP ? "DP"
782                : REGNO (addr) == REG_SP ? "SP"
783                : REGNO (addr) == REG_IP ? "IP"
784                : REGNO (addr) == REG_VFP ? "VFP" /* Should never see this  */
785                : REGNO (addr) == REG_AP ? "AP"   /*  or this, either.  */
786                : reg_names[REGNO (addr)]);
787       break;
788
789     case PRE_DEC:
790     case POST_INC:
791       abort ();
792       break;
793
794     case CONST:
795       addr = XEXP (addr, 0);
796       print_operand_address (file, XEXP (addr, 0));
797       fprintf (file, "+");
798       print_operand_address (file, XEXP (addr, 1));
799       return;
800
801     case LO_SUM:
802       if (is_regfile_address (XEXP (addr, 1)))
803         fprintf (file, "%%lo8data(");
804       else
805         fprintf (file, "%%lo8insn(");
806       print_operand_address (file, XEXP (addr, 1));
807       fprintf (file, ")");
808       print_operand_address (file, XEXP (addr, 0));
809       break;
810                
811     case PLUS:                  /* Ought to be stack or dp references.  */
812       if (XEXP (addr, 1) == const0_rtx
813           && GET_CODE (XEXP (addr, 0)) == PLUS)
814         {
815           print_operand_address (file, XEXP (addr, 0));
816           return;
817         }
818
819       if (! REG_P (XEXP (addr, 0)) || REGNO (XEXP (addr, 0)) != REG_IP)
820         print_operand_address (file, XEXP (addr, 1)); /* const  */
821       print_operand_address (file, XEXP (addr, 0));   /* (reg)  */
822       break;
823
824     case HIGH:
825       if (is_regfile_address (XEXP (addr, 0)))
826         fprintf (file, "%%hi8data(");
827       else
828         fprintf (file, "%%hi8insn(");
829       output_addr_const (file, XEXP (addr, 0));
830       fprintf (file, ")");
831       break;
832
833     default:
834       output_addr_const (file, addr);
835     }
836 }
837
838
839 /* Output X as assembler operand to file FILE.  */
840      
841 void
842 print_operand (FILE *file, rtx x, int code)
843 {
844   int abcd = 0;
845   unsigned long value;
846
847   switch (code)
848     {
849     case '<':                   /* Push */
850       ip2k_stack_delta++;
851       return;
852
853     case '>':                   /* Pop */
854       ip2k_stack_delta--;
855       return;
856
857     case 'A':
858     case 'B':
859     case 'C':
860     case 'D':
861       abcd = code - 'A';
862       break;
863
864     case 'H':
865       abcd = 0;
866       break;
867
868     case 'L':
869       abcd = 1;
870       break;
871
872     case 'S':
873     case 'T':
874     case 'U':
875     case 'V':
876     case 'W':
877     case 'X':
878     case 'Y':
879     case 'Z':
880       abcd = code - 'S';
881
882     default:
883       break;
884     }
885
886   if (ip2k_short_operand (x, GET_MODE (x))
887       && ip2k_address_uses_reg_p (x, REG_SP))
888     /* An SP-relative address needs to account for interior stack
889        pushes that reload didn't know about when it calculated the
890        stack offset.  */
891     abcd += ip2k_stack_delta;
892
893   switch (GET_CODE (x))
894     {
895     case SUBREG:
896       x = alter_subreg (&x);
897       /* fall-through  */
898
899     case REG:
900       fprintf (file, reg_names[true_regnum (x) + abcd]);
901       break;
902
903     case CONST_INT:
904       switch (code)
905         {
906         case 'x':
907           fprintf (file, "$%x", (int)(INTVAL (x) & 0xffff));
908           break;
909
910         case 'b':
911           fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); /* bit selector  */
912           break;
913
914         case 'e':               /* "1 << n" - e.g. "exp"  */
915           fprintf (file, "#%d", 1 << INTVAL (x));
916           break;
917
918         case 'A':
919         case 'B':
920         case 'C':
921         case 'D':
922           value = INTVAL (x);
923           value >>= 8 * (3 - abcd);
924           value &= 0xff;
925
926           fprintf (file, "#%ld", value);
927           break;
928
929         case 'H':
930           fprintf (file, "#%d", (int)((INTVAL (x) >> 8) & 0xff));
931           break;
932
933         case 'L':
934           fprintf (file, "#%d", (int)(INTVAL (x) & 0xff));
935           break;
936
937         case 'S':
938         case 'T':
939         case 'U':
940         case 'V':
941         case 'W':
942         case 'X':
943         case 'Y':
944         case 'Z':
945           value = ((unsigned long long)INTVAL (x)) >> (8 * (7 - abcd)) & 0xff;
946           fprintf (file, "#%ld", value);
947           break;
948
949         default:
950           fprintf (file, "#" HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
951         }
952       break;
953
954     case SYMBOL_REF:
955     case LABEL_REF:
956     case CODE_LABEL:
957     case CONST:
958       switch (code)
959         {
960         case 'A':
961         case 'B':
962         case 'C':
963         case 'D':
964         case 'S':
965         case 'T':
966         case 'U':
967         case 'V':
968         case 'W':
969         case 'X':
970         case 'Y':
971         case 'Z':
972           abort ();             /* Probably an error.  */
973           break;
974
975         case 'H':
976           fprintf (file, "#%s(",
977                    is_regfile_address (x) ? "%hi8data"
978                                           : "%hi8insn");
979           print_operand_address (file, x);
980           fputc (')', file);
981           break;
982
983         case 'L':
984           fprintf (file, "#%s(",
985                    is_regfile_address (x) ? "%lo8data"
986                                           : "%lo8insn");
987           print_operand_address (file, x);
988           fputc (')', file);
989           break;
990
991         default:
992           print_operand_address (file, x);
993         }
994       break;
995
996     case MEM:
997       {
998         rtx addr = XEXP (x, 0);
999
1000         if (GET_CODE (addr) == SUBREG)
1001           addr = alter_subreg (&x);
1002
1003         if (CONSTANT_P (addr) && abcd)  
1004           {
1005             fputc ('(', file);
1006             print_operand_address (file, addr);
1007             fprintf (file, ")+%d", abcd);
1008           }
1009         else if (abcd)
1010           {
1011             switch (GET_CODE (addr))
1012               {
1013               case PLUS:
1014                 abcd += INTVAL (XEXP (addr, 1));
1015
1016                 /* Worry about (plus (plus (reg DP) (const_int 10))
1017                                            (const_int 0))  */
1018                 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1019                   {
1020                     addr = XEXP (addr, 0);
1021                     abcd += INTVAL (XEXP (addr, 1));
1022                   }
1023                        
1024                 fprintf (file, "%d", abcd);
1025                 print_operand_address (file, XEXP (addr, 0));
1026                 break;
1027
1028               case REG:
1029               default:
1030                 fprintf (file, "%d", abcd);
1031                 print_operand_address (file, addr);
1032               }
1033           }
1034         else if (GET_CODE (addr) == REG
1035                  && (REGNO (addr) == REG_DP || REGNO (addr) == REG_SP))
1036           {
1037             fprintf (file, "0");
1038             print_operand_address (file, addr);
1039           }
1040         else
1041           print_operand_address (file, addr);
1042       }
1043       break;
1044
1045     case CONST_DOUBLE:
1046       /* Is this an integer or a floating point value?  */
1047       if (GET_MODE (x) == VOIDmode)
1048         {
1049           switch (code)
1050             {
1051             case 'S':
1052             case 'T':
1053             case 'U':
1054             case 'V':
1055               value = CONST_DOUBLE_HIGH (x);
1056               value >>= 8 * (3 - abcd);
1057               value &= 0xff;
1058
1059               fprintf (file, "#%ld", value);
1060               break;
1061
1062             case 'W':
1063             case 'X':
1064             case 'Y':
1065             case 'Z':
1066               value = CONST_DOUBLE_LOW (x);
1067               value >>= 8 * (7 - abcd);
1068               value &= 0xff;
1069
1070               fprintf (file, "#%ld", value);
1071               break;
1072             }
1073
1074         }
1075       else
1076         {
1077           REAL_VALUE_TYPE rv;
1078
1079           REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1080           REAL_VALUE_TO_TARGET_SINGLE (rv, value);
1081           fprintf (file, "0x%lx", value);
1082         }
1083       break;
1084
1085     default:
1086       fatal_insn ("bad operand", x);
1087     }
1088 }
1089 \f
1090 /* Remember the operands for the compare.  */
1091 const char *
1092 ip2k_set_compare (rtx x, rtx y)
1093 {
1094   ip2k_compare_operands[0] = x;
1095   ip2k_compare_operands[1] = y;
1096   return "";
1097 }
1098
1099 /* Emit the code for sCOND instructions.  */
1100 const char *
1101 ip2k_gen_sCOND (rtx insn ATTRIBUTE_UNUSED, enum rtx_code code, rtx dest)
1102 {
1103 #define operands ip2k_compare_operands
1104   enum machine_mode mode;
1105
1106   operands[2] = dest;
1107
1108   mode = GET_MODE (operands[0]);
1109   if ((mode != QImode) && (mode != HImode)
1110       && (mode != SImode) && (mode != DImode))
1111     mode = GET_MODE (operands[1]);
1112
1113   /* We have a fast path for a specific type of QImode compare.  We ought
1114      to extend this for larger cases too but that wins less frequently and
1115      introduces a lot of complexity.  */
1116   if (mode == QImode
1117       && !rtx_equal_p (operands[0], operands[2])
1118       && !rtx_equal_p (operands[1], operands[2])
1119       && (! REG_P (operands[2])
1120           || (ip2k_xexp_not_uses_reg_p (operands[0], REGNO (operands[2]), 1)
1121               && ip2k_xexp_not_uses_reg_p (operands[1],
1122                                            REGNO (operands[2]), 1))))
1123     {
1124       OUT_AS1 (clr, %2);
1125       if (immediate_operand (operands[1], QImode)
1126           && ((INTVAL (operands[1]) & 0xff) == 0xff))
1127         {
1128           if (code == EQ)
1129             OUT_AS2 (incsnz, w, %0);
1130           else
1131             OUT_AS2 (incsz, w, %0);
1132         }
1133       else if (immediate_operand (operands[1], QImode)
1134                && ((INTVAL (operands[1]) & 0xff) == 0x01))
1135         {
1136           if (code == EQ)
1137             OUT_AS2 (decsnz, w, %0);
1138           else
1139             OUT_AS2 (decsz, w, %0);
1140         }
1141       else if (ip2k_compare_operands[1] == const0_rtx)
1142         {
1143           OUT_AS2 (mov, w, %0);
1144           if (code == EQ)
1145             OUT_AS1 (snz,);
1146           else
1147             OUT_AS1 (sz,);
1148         }
1149       else
1150         {
1151           OUT_AS2 (mov, w, %0);
1152           if (code == EQ)
1153             OUT_AS2 (csne, w, %1);
1154           else
1155             OUT_AS2 (cse, w, %1);
1156         }
1157       OUT_AS1 (inc, %2);
1158     }
1159   else
1160     {
1161       if (ip2k_compare_operands[1] == const0_rtx)
1162         {
1163           switch (mode)
1164             {
1165             case QImode:
1166               OUT_AS2 (mov, w, %0);
1167               break;
1168
1169             case HImode:
1170               OUT_AS2 (mov, w, %H0);
1171               OUT_AS2 (or, w, %L0);
1172               break;
1173
1174             case SImode:
1175               OUT_AS2 (mov, w, %A0);
1176               OUT_AS2 (or, w, %B0);
1177               OUT_AS2 (or, w, %C0);
1178               OUT_AS2 (or, w, %D0);
1179               break;
1180
1181             case DImode:
1182               OUT_AS2 (mov, w, %S0);
1183               OUT_AS2 (or, w, %T0);
1184               OUT_AS2 (or, w, %U0);
1185               OUT_AS2 (or, w, %V0);
1186               OUT_AS2 (or, w, %W0);
1187               OUT_AS2 (or, w, %X0);
1188               OUT_AS2 (or, w, %Y0);
1189               OUT_AS2 (or, w, %Z0);
1190               break;
1191
1192             default:
1193               abort ();
1194             }
1195         }
1196       else
1197         {
1198           switch (mode)
1199             {
1200             case QImode:
1201               OUT_AS2 (mov, w, %1);
1202               OUT_AS2 (cmp, w, %0);
1203               break;
1204
1205             case HImode:
1206               OUT_AS2 (mov, w, %H1);
1207               OUT_AS2 (cmp, w, %H0);
1208               OUT_AS1 (sz,);
1209               OUT_AS1 (page, 2f);
1210               OUT_AS1 (jmp, 2f);
1211               OUT_AS2 (mov, w, %L1);
1212               OUT_AS2 (cmp, w, %L0);
1213               OUT_AS1 (2:,);
1214               break;
1215
1216             case SImode:
1217               if (code == EQ)
1218                 {
1219                   OUT_AS2 (mov, w, #1);
1220                   OUT_AS2 (mov, mulh, w);
1221                 }
1222               else
1223                 OUT_AS1 (clr, mulh);
1224               OUT_AS2 (mov, w, %A1);
1225               OUT_AS2 (cse, w, %A0);
1226               OUT_AS1 (page, 2f);
1227               OUT_AS1 (jmp, 2f);
1228               OUT_AS2 (mov, w, %B1);
1229               OUT_AS2 (cse, w, %B0);
1230               OUT_AS1 (page, 2f);
1231               OUT_AS1 (jmp, 2f);
1232               OUT_AS2 (mov, w, %C1);
1233               OUT_AS2 (cse, w, %C0);
1234               OUT_AS1 (page, 2f);
1235               OUT_AS1 (jmp, 2f);
1236               OUT_AS2 (mov, w, %D1);
1237               OUT_AS2 (cse, w, %D0);
1238               OUT_AS1 (2:,);
1239               if (code == EQ)
1240                 OUT_AS1 (dec, mulh);
1241               else
1242                 OUT_AS1 (inc, mulh);
1243               OUT_AS2 (mov, w, mulh);
1244               OUT_AS2 (mov, %2, w);
1245               return "";
1246
1247             case DImode:
1248               if (code == EQ)
1249                 {
1250                   OUT_AS2 (mov, w, #1);
1251                   OUT_AS2 (mov, mulh, w);
1252                 }
1253               else
1254                 OUT_AS1 (clr, mulh);
1255               OUT_AS2 (mov, w, %S1);
1256               OUT_AS2 (cse, w, %S0);
1257               OUT_AS1 (page, 2f);
1258               OUT_AS1 (jmp, 2f);
1259               OUT_AS2 (mov, w, %T1);
1260               OUT_AS2 (cse, w, %T0);
1261               OUT_AS1 (page, 2f);
1262               OUT_AS1 (jmp, 2f);
1263               OUT_AS2 (mov, w, %U1);
1264               OUT_AS2 (cse, w, %U0);
1265               OUT_AS1 (page, 2f);
1266               OUT_AS1 (jmp, 2f);
1267               OUT_AS2 (mov, w, %V1);
1268               OUT_AS2 (cse, w, %V0);
1269               OUT_AS1 (page, 2f);
1270               OUT_AS1 (jmp, 2f);
1271               OUT_AS2 (mov, w, %W1);
1272               OUT_AS2 (cse, w, %W0);
1273               OUT_AS1 (page, 2f);
1274               OUT_AS1 (jmp, 2f);
1275               OUT_AS2 (mov, w, %X1);
1276               OUT_AS2 (cse, w, %X0);
1277               OUT_AS1 (page, 2f);
1278               OUT_AS1 (jmp, 2f);
1279               OUT_AS2 (mov, w, %Y1);
1280               OUT_AS2 (cse, w, %Y0);
1281               OUT_AS1 (page, 2f);
1282               OUT_AS1 (jmp, 2f);
1283               OUT_AS2 (mov, w, %Z1);
1284               OUT_AS2 (cse, w, %Z0);
1285               OUT_AS1 (2:,);
1286               if (code == EQ)
1287                 OUT_AS1 (dec, mulh);
1288               else
1289                 OUT_AS1 (inc, mulh);
1290               OUT_AS2 (mov, w, mulh);
1291               OUT_AS2 (mov, %2, w);
1292               return "";
1293
1294             default:
1295               abort ();
1296             }
1297         }
1298       OUT_AS2 (mov, w, #0);
1299       if (code == EQ)
1300         OUT_AS1 (snz,);
1301       else
1302         OUT_AS1 (sz,);
1303       OUT_AS1 (inc, wreg);
1304       OUT_AS2 (mov, %2, w);
1305     }
1306
1307   return "";
1308 #undef operands
1309 }
1310
1311 const char *
1312 ip2k_gen_signed_comp_branch (rtx insn, enum rtx_code code, rtx label)
1313 {
1314 #define operands ip2k_compare_operands
1315   enum machine_mode mode;
1316   int can_use_skip = 0;
1317   rtx ninsn;
1318
1319   operands[2] = label;
1320
1321   mode = GET_MODE (operands[0]);
1322   if ((mode != QImode) && (mode != HImode)
1323       && (mode != SImode) && (mode != DImode))
1324     mode = GET_MODE (operands[1]);
1325
1326   /* Look for situations where we can just skip the next instruction instead
1327      of skipping and then branching!  */
1328   ninsn = next_real_insn (insn);
1329   if (ninsn
1330       && (recog_memoized (ninsn) >= 0)
1331       && get_attr_skip (ninsn) == SKIP_YES)
1332     {
1333       rtx skip_tgt = next_nonnote_insn (next_real_insn (insn));
1334
1335       /* The first situation is where the target of the jump is one insn
1336          after the jump insn and the insn being jumped is only one machine
1337          opcode long.  */
1338       if (label == skip_tgt)
1339         can_use_skip = 1;
1340       else
1341         {
1342           /* If our skip target is in fact a code label then we ignore the
1343              label and move onto the next useful instruction.  Nothing we do
1344              here has any effect on the use of skipping instructions.  */
1345           if (GET_CODE (skip_tgt) == CODE_LABEL)
1346             skip_tgt = next_nonnote_insn (skip_tgt);
1347
1348           /* The second situation is where we have something of the form:
1349
1350                test_condition
1351                skip_conditional
1352                page/jump label
1353
1354              optional_label (this may or may not exist):
1355                skippable_insn
1356                page/jump label
1357
1358              In this case we can eliminate the first "page/jump label".  */
1359           if (GET_CODE (skip_tgt) == JUMP_INSN)
1360             {
1361               rtx set = single_set (skip_tgt);
1362               if (GET_CODE (XEXP (set, 0)) == PC
1363                   && GET_CODE (XEXP (set, 1)) == LABEL_REF
1364                   && label == JUMP_LABEL (skip_tgt))
1365                 can_use_skip = 2;
1366             }
1367         }
1368     }
1369
1370   /* gcc is a little braindead and does some rather stateful things while
1371      inspecting attributes - we have to put this state back to what it's
1372      supposed to be.  */
1373   extract_constrain_insn_cached (insn);
1374
1375   if (ip2k_compare_operands[1] == const0_rtx) /* These are easier.  */
1376     {
1377       switch (code)
1378         {
1379         case LT:
1380           if (can_use_skip)
1381             {
1382               OUT_AS2 (sb, %0, 7);
1383             }
1384           else
1385             {
1386               OUT_AS2 (snb, %0, 7);
1387               OUT_AS1 (page, %2);
1388               OUT_AS1 (jmp, %2);
1389             }
1390           break;
1391
1392         case GT:
1393           switch (mode)
1394             {
1395             case DImode:
1396               OUT_AS2 (rl, w, %S0);
1397               OUT_AS2 (mov, w, %S0);
1398               OUT_AS2 (or, w, %T0);
1399               OUT_AS2 (or, w, %U0);
1400               OUT_AS2 (or, w, %V0);
1401               OUT_AS2 (or, w, %W0);
1402               OUT_AS2 (or, w, %X0);
1403               OUT_AS2 (or, w, %Y0);
1404               OUT_AS2 (or, w, %Z0);
1405               OUT_AS1 (snz, );
1406               OUT_AS2 (setb, status, 0);
1407               OUT_AS2 (sb, status, 0);
1408               OUT_AS1 (page, %2);
1409               OUT_AS1 (jmp, %2);
1410               break;
1411
1412             case SImode:
1413               OUT_AS2 (rl, w, %A0);
1414               OUT_AS2 (mov, w, %A0);
1415               OUT_AS2 (or, w, %B0);
1416               OUT_AS2 (or, w, %C0);
1417               OUT_AS2 (or, w, %D0);
1418               OUT_AS1 (snz, );
1419               OUT_AS2 (setb, status, 0);
1420               OUT_AS2 (sb, status, 0);
1421               OUT_AS1 (page, %2);
1422               OUT_AS1 (jmp, %2);
1423               break;
1424
1425             case HImode:
1426               OUT_AS2 (rl, w, %H0);
1427               OUT_AS2 (mov, w, %H0);
1428               OUT_AS2 (or, w, %L0);
1429               OUT_AS1 (snz, );
1430               OUT_AS2 (setb, status, 0);
1431               OUT_AS2 (sb, status, 0);
1432               OUT_AS1 (page, %2);
1433               OUT_AS1 (jmp, %2);
1434               break;
1435
1436             case QImode:
1437               OUT_AS2 (mov, w, %0);     /* Will just do "sb w, 7".  */
1438               OUT_AS1 (snz, );
1439               OUT_AS2 (setb, wreg, 7);
1440               OUT_AS2 (sb, wreg, 7);
1441               OUT_AS1 (page, %2);
1442               OUT_AS1 (jmp, %2);
1443               break;
1444
1445             default:
1446               abort ();
1447             }
1448           break;
1449
1450         case LE:
1451           switch (mode)
1452             {
1453             case DImode:
1454               OUT_AS2 (mov, w, %S0);
1455               OUT_AS2 (or, w, %T0);
1456               OUT_AS2 (or, w, %U0);
1457               OUT_AS2 (or, w, %V0);
1458               OUT_AS2 (or, w, %W0);
1459               OUT_AS2 (or, w, %X0);
1460               OUT_AS2 (or, w, %Y0);
1461               OUT_AS2 (or, w, %Z0);     /* Z is correct.  */
1462               OUT_AS1 (sz, );
1463               OUT_AS2 (snb, %S0, 7);
1464               OUT_AS1 (page, %2);
1465               OUT_AS1 (jmp, %2);
1466               break;
1467
1468             case SImode:
1469               OUT_AS2 (mov, w, %A0);
1470               OUT_AS2 (or, w, %B0);
1471               OUT_AS2 (or, w, %C0);
1472               OUT_AS2 (or, w, %D0);     /* Z is correct.  */
1473               OUT_AS1 (sz, );
1474               OUT_AS2 (snb, %A0, 7);
1475               OUT_AS1 (page, %2);
1476               OUT_AS1 (jmp, %2);
1477               break;
1478
1479             case HImode:
1480               OUT_AS2 (mov, w, %H0);
1481               OUT_AS2 (or, w, %L0);
1482               OUT_AS1 (sz, );
1483               OUT_AS2 (snb, %H0, 7);
1484               OUT_AS1 (page, %2);
1485               OUT_AS1 (jmp, %2);
1486               break;
1487
1488             case QImode:
1489               OUT_AS2 (mov, w, %0);     /* Will just do "sb w, 7".  */
1490               OUT_AS1 (sz, );
1491               OUT_AS2 (snb, wreg, 7);
1492               OUT_AS1 (page, %2);
1493               OUT_AS1 (jmp, %2);
1494               break;
1495
1496             default:
1497               abort ();
1498             }
1499           break;
1500
1501         case GE:
1502           if (can_use_skip)
1503             {
1504               OUT_AS2 (snb, %0, 7);
1505             }
1506           else
1507             {
1508               OUT_AS2 (sb, %0, 7);
1509               OUT_AS1 (page, %2);
1510               OUT_AS1 (jmp, %2);
1511             }
1512           break;
1513
1514         default:
1515           abort ();
1516         }
1517       return "";
1518     }
1519
1520   /* signed compares are out of line because we can't get
1521      the hardware to compute the overflow for us.  */
1522
1523   switch (mode)
1524     {
1525     case QImode:
1526       OUT_AS1 (push, %1%<);
1527       OUT_AS1 (push, %0%>);
1528       OUT_AS1 (page, __cmpqi2);
1529       OUT_AS1 (call, __cmpqi2);
1530       break;
1531
1532     case HImode:
1533       OUT_AS1 (push, %L1%<);
1534       OUT_AS1 (push, %H1%<);
1535       OUT_AS1 (push, %L0%<);
1536       OUT_AS1 (push, %H0%>%>%>);
1537       OUT_AS1 (page, __cmphi2);
1538       OUT_AS1 (call, __cmphi2);
1539       break;
1540
1541     case SImode:
1542       OUT_AS1 (push, %D1%<);
1543       OUT_AS1 (push, %C1%<);
1544       OUT_AS1 (push, %B1%<);
1545       OUT_AS1 (push, %A1%<);
1546       OUT_AS1 (push, %D0%<);
1547       OUT_AS1 (push, %C0%<);
1548       OUT_AS1 (push, %B0%<);
1549       OUT_AS1 (push, %A0%>%>%>%>%>%>%>);
1550       OUT_AS1 (page, __cmpsi2);
1551       OUT_AS1 (call, __cmpsi2);
1552       break;
1553   
1554     case DImode:
1555       if (GET_CODE (operands[0]) == MEM
1556           && true_regnum (XEXP (operands[0], 0)) == REG_DP)
1557         {
1558           OUT_AS1 (push, %Z1%<);
1559           OUT_AS1 (push, %Y1%<);
1560           OUT_AS1 (push, %X1%<);
1561           OUT_AS1 (push, %W1%<);
1562           OUT_AS1 (push, %V1%<);
1563           OUT_AS1 (push, %U1%<);
1564           OUT_AS1 (push, %T1%<);
1565           OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
1566           OUT_AS1 (page, __cmpdi2_dp);
1567           OUT_AS1 (call, __cmpdi2_dp);
1568         }
1569       else
1570         {
1571           OUT_AS1 (push, %Z1%<);
1572           OUT_AS1 (push, %Y1%<);
1573           OUT_AS1 (push, %X1%<);
1574           OUT_AS1 (push, %W1%<);
1575           OUT_AS1 (push, %V1%<);
1576           OUT_AS1 (push, %U1%<);
1577           OUT_AS1 (push, %T1%<);
1578           OUT_AS1 (push, %S1%<);
1579           OUT_AS1 (push, %Z0%<);
1580           OUT_AS1 (push, %Y0%<);
1581           OUT_AS1 (push, %X0%<);
1582           OUT_AS1 (push, %W0%<);
1583           OUT_AS1 (push, %V0%<);
1584           OUT_AS1 (push, %U0%<);
1585           OUT_AS1 (push, %T0%<);
1586           OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
1587           OUT_AS1 (page, __cmpdi2);
1588           OUT_AS1 (call, __cmpdi2);
1589         }
1590       break;
1591
1592     default:
1593       abort ();
1594   }
1595
1596   switch (code)
1597     {
1598     case LT:
1599       if (can_use_skip)
1600         {
1601           OUT_AS2 (cse, w, #0);
1602         }
1603       else
1604         {
1605           OUT_AS2 (csne, w, #0);
1606           OUT_AS1 (page, %2);
1607           OUT_AS1 (jmp, %2);
1608         }
1609       break;
1610       
1611     case GT:
1612       if (can_use_skip)
1613         {
1614           OUT_AS2 (cse, w, #2);
1615         }
1616       else
1617         {
1618           OUT_AS2 (csne, w, #2);
1619           OUT_AS1 (page, %2);
1620           OUT_AS1 (jmp, %2);
1621         }
1622       break;
1623
1624     case LE:
1625       if (can_use_skip)
1626         {
1627           OUT_AS2 (snb, wreg, 1);
1628         }
1629       else
1630         {
1631           OUT_AS2 (sb, wreg, 1);
1632           OUT_AS1 (page, %2);
1633           OUT_AS1 (jmp, %2);
1634         }
1635       break;
1636
1637     case GE:
1638       if (can_use_skip)
1639         {
1640           OUT_AS2 (csne, w, #0);
1641         }
1642       else
1643         {
1644           OUT_AS2 (cse, w, #0);
1645           OUT_AS1 (page, %2);
1646           OUT_AS1 (jmp, %2);
1647         }
1648       break;
1649       
1650     default:
1651       abort ();
1652     }
1653   return "";
1654 #undef operands
1655 }
1656
1657 const char *
1658 ip2k_gen_unsigned_comp_branch (rtx insn, enum rtx_code code, rtx label)
1659 {
1660 #define operands ip2k_compare_operands
1661   enum machine_mode mode;
1662   int imm_sub = 0;
1663   int imm_cmp = 0;
1664   int can_use_skip = 0;
1665   rtx ninsn;
1666   HOST_WIDE_INT const_low;
1667   HOST_WIDE_INT const_high;
1668
1669   operands[2] = label;
1670
1671   mode = GET_MODE (operands[0]);
1672   if ((mode != QImode) && (mode != HImode) && (mode != SImode)
1673       && (mode != DImode))
1674     {
1675       mode = GET_MODE (operands[1]);
1676     }
1677
1678   /* Look for situations where we can just skip the next instruction instead
1679      of skipping and then branching!  */
1680   ninsn = next_real_insn (insn);
1681   if (ninsn
1682       && (recog_memoized (ninsn) >= 0)
1683       && get_attr_skip (ninsn) == SKIP_YES)
1684     {
1685       rtx skip_tgt = next_nonnote_insn (next_real_insn (insn));
1686
1687       /* The first situation is where the target of the jump is one insn
1688          after the jump insn and the insn being jumped is only one machine
1689          opcode long.  */
1690       if (label == skip_tgt)
1691         can_use_skip = 1;
1692       else
1693         {
1694           /* If our skip target is in fact a code label then we ignore the
1695              label and move onto the next useful instruction.  Nothing we do
1696              here has any effect on the use of skipping instructions.  */
1697           if (GET_CODE (skip_tgt) == CODE_LABEL)
1698             skip_tgt = next_nonnote_insn (skip_tgt);
1699
1700           /* The second situation is where we have something of the form:
1701
1702                test_condition
1703                skip_conditional
1704                page/jump label
1705
1706              optional_label (this may or may not exist):
1707                skippable_insn
1708                page/jump label
1709
1710              In this case we can eliminate the first "page/jump label".  */
1711           if (GET_CODE (skip_tgt) == JUMP_INSN)
1712             {
1713               rtx set = single_set (skip_tgt);
1714               if (GET_CODE (XEXP (set, 0)) == PC
1715                   && GET_CODE (XEXP (set, 1)) == LABEL_REF
1716                   && label == JUMP_LABEL (skip_tgt))
1717                 can_use_skip = 2;
1718             }
1719         }
1720     }
1721
1722   /* gcc is a little braindead and does some rather stateful things while
1723      inspecting attributes - we have to put this state back to what it's
1724      supposed to be.  */
1725   extract_constrain_insn_cached (insn);
1726
1727   if (ip2k_compare_operands[1] == const0_rtx)
1728     {
1729       switch (code)
1730         {
1731         case LEU:
1732           code = EQ;                    /* Nothing is LTU 0.  */
1733           goto zero;
1734
1735         case GTU:                       
1736           code = NE;                    /* Anything nonzero is GTU.  */
1737           /* fall-through  */
1738
1739         case EQ:
1740         case NE:                        /* Test all the bits, result in
1741                                            Z AND WREG.  */
1742         zero:
1743           switch (mode)
1744             {
1745             case DImode:
1746               OUT_AS2 (mov, w, %S0);
1747               OUT_AS2 (or, w, %T0);
1748               OUT_AS2 (or, w, %U0);
1749               OUT_AS2 (or, w, %V0);
1750               OUT_AS2 (or, w, %W0);
1751               OUT_AS2 (or, w, %X0);
1752               OUT_AS2 (or, w, %Y0);
1753               OUT_AS2 (or, w, %Z0);
1754               break;
1755
1756             case SImode:
1757               OUT_AS2 (mov, w, %A0);
1758               OUT_AS2 (or, w, %B0);
1759               OUT_AS2 (or, w, %C0);
1760               OUT_AS2 (or, w, %D0);
1761               break;
1762
1763             case HImode:
1764               OUT_AS2 (mov, w, %H0);
1765               OUT_AS2 (or, w, %L0);
1766               break;
1767
1768             case QImode:
1769               OUT_AS2 (mov, w, %0);
1770               break;
1771
1772             default:
1773               abort ();
1774             }
1775
1776           if (can_use_skip)
1777             {
1778               if (code == EQ)
1779                 OUT_AS1 (sz, );
1780               else
1781                 OUT_AS1 (snz, );
1782             }
1783           else
1784             {
1785               if (code == EQ)
1786                 OUT_AS1 (snz,);
1787               else
1788                 OUT_AS1 (sz,);
1789               OUT_AS1 (page, %2);
1790               OUT_AS1 (jmp, %2);
1791             }
1792           break;
1793
1794         case GEU:
1795           /* Always succeed.  */
1796           OUT_AS1 (page, %2);
1797           OUT_AS1 (jmp, %2);
1798           break;
1799
1800         case LTU:                       
1801           /* Always fail.  */
1802           break;
1803
1804         default:
1805           abort ();
1806         }
1807       return "";
1808     }
1809
1810   /* Look at whether we have a constant as one of our operands.  If we do
1811      and it's in the position that we use to subtract from during our
1812      normal optimized comparison concept then we have to shuffle things
1813      around!  */
1814   if (mode != QImode)
1815     {
1816       if ((immediate_operand (operands[1], GET_MODE (operands[1]))
1817            && ((code == LEU) || (code == GTU)))
1818           || (immediate_operand (operands[0], GET_MODE (operands[0]))
1819               && ((code == LTU) || (code == GEU))))
1820         {
1821           imm_sub = 1;
1822         }
1823     }
1824
1825   /* Same as above - look if we have a constant that we can compare
1826      for equality or non-equality.  If we know this then we can look
1827      for common value eliminations.  Note that we want to ensure that
1828      any immediate value is operand 1 to simplify the code later!  */
1829   if ((code == EQ) || (code == NE))
1830     {
1831       imm_cmp = immediate_operand (operands[1], GET_MODE (operands[1]));
1832       if (! imm_cmp)
1833         {
1834           imm_cmp = immediate_operand (operands[0], GET_MODE (operands[0]));
1835           if (imm_cmp)
1836             {
1837               rtx tmp = operands[1];
1838               operands[1] = operands[0];
1839               operands[0] = tmp;
1840             }
1841         }
1842     }
1843   
1844   switch (mode)
1845     {
1846     case QImode:
1847       switch (code)
1848         {
1849         case EQ:
1850           if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff))
1851             OUT_AS2 (incsnz, w, %0);
1852           else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01))
1853             OUT_AS2 (decsnz, w, %0);
1854           else
1855             {
1856               OUT_AS2 (mov, w, %1);
1857               OUT_AS2 (csne, w, %0);
1858             }
1859           OUT_AS1 (page, %2);
1860           OUT_AS1 (jmp, %2);
1861           break;
1862
1863         case NE:
1864           if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff))
1865             OUT_AS2 (incsz, w, %0);
1866           else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01))
1867             OUT_AS2 (decsz, w, %0);
1868           else
1869             {
1870               OUT_AS2 (mov, w, %1);
1871               OUT_AS2 (cse, w, %0);
1872             }
1873           OUT_AS1 (page, %2);
1874           OUT_AS1 (jmp, %2);
1875           break;
1876
1877         case GTU:
1878           OUT_AS2 (mov, w, %0);
1879           OUT_AS2 (cmp, w, %1);
1880           OUT_AS1 (sc,);
1881           OUT_AS1 (page, %2);
1882           OUT_AS1 (jmp, %2);
1883           break;
1884
1885         case GEU:
1886           OUT_AS2 (mov, w, %1);
1887           OUT_AS2 (cmp, w, %0);
1888           OUT_AS1 (snc,);
1889           OUT_AS1 (page, %2);
1890           OUT_AS1 (jmp, %2);
1891           break;
1892
1893         case LTU:
1894           OUT_AS2 (mov, w, %1);
1895           OUT_AS2 (cmp, w, %0);
1896           OUT_AS1 (sc,);
1897           OUT_AS1 (page, %2);
1898           OUT_AS1 (jmp, %2);
1899           break;
1900
1901         case LEU:
1902           OUT_AS2 (mov, w, %0);
1903           OUT_AS2 (cmp, w, %1);
1904           OUT_AS1 (snc,);
1905           OUT_AS1 (page, %2);
1906           OUT_AS1 (jmp, %2);
1907           break;
1908
1909         default:
1910           abort ();
1911         }
1912       break;
1913
1914     case HImode:
1915       switch (code)
1916         {
1917         case EQ:
1918           {
1919             unsigned char h = 0, l = 1;
1920
1921             if (imm_cmp)
1922               {
1923                 h = (INTVAL (operands[1]) >> 8) & 0xff;
1924                 l = INTVAL (operands[1]) & 0xff;
1925
1926                 if ((h == 0xff) && (l == 0xff))
1927                   {
1928                     /* We should be able to do the following, but the
1929                        IP2k simulator doesn't like it and we get a load
1930                        of failures in gcc-c-torture.  */
1931                     OUT_AS2 (incsnz, w, %L0);
1932                     OUT_AS2 (incsz, w, %H0);
1933 /*                  OUT_AS1 (skip,);               Should have this  */
1934                     OUT_AS1 (page, 1f);/* Shouldn't need this!  */
1935                     OUT_AS1 (jmp, 1f); /* Shouldn't need this either.  */
1936                     OUT_AS1 (page, %2);
1937                     OUT_AS1 (jmp, %2);
1938                     OUT_AS1 (1:,);
1939                     break;
1940                   }
1941                 else if (h == 0)
1942                   {
1943                     if (l == 1)
1944                       OUT_AS2 (dec, w, %L0);
1945                     else
1946                       {
1947                         OUT_AS2 (mov, w, %L0);
1948                         OUT_AS2 (sub, w, %L1);
1949                       }
1950                     OUT_AS2 (or, w, %H0);
1951                     OUT_AS1 (snz,);
1952                     OUT_AS1 (page, %2);
1953                     OUT_AS1 (jmp, %2);
1954                     break;
1955                   }
1956                 else if (l == 0)
1957                   {
1958                     if (h == 1)
1959                       OUT_AS2 (dec, w, %H0);
1960                     else
1961                       {
1962                         OUT_AS2 (mov, w, %H0);
1963                         OUT_AS2 (sub, w, %H1);
1964                       }
1965                     OUT_AS2 (or, w, %L0);
1966                     OUT_AS1 (snz,);
1967                     OUT_AS1 (page, %2);
1968                     OUT_AS1 (jmp, %2);
1969                     break;
1970                   }
1971               }
1972
1973             OUT_AS2 (mov, w, %H1);
1974             OUT_AS2 (cse, w, %H0);
1975             OUT_AS1 (page, 2f);
1976             OUT_AS1 (jmp, 2f);
1977             if (! imm_cmp || (h != l))
1978               OUT_AS2 (mov, w, %L1);
1979             OUT_AS2 (csne, w, %L0);
1980             OUT_AS1 (page, %2);
1981             OUT_AS1 (jmp, %2);
1982             OUT_AS1 (2:,);
1983           }
1984           break;
1985
1986         case NE:
1987           {
1988             unsigned char h = 0, l = 1;
1989
1990             if (imm_cmp)
1991               {
1992                 h = (INTVAL (operands[1]) >> 8) & 0xff;
1993                 l = INTVAL (operands[1]) & 0xff;
1994
1995                 if ((h == 0xff) && (l == 0xff))
1996                   {
1997                     OUT_AS2 (incsnz, w, %L0);
1998                     OUT_AS2 (incsz, w, %H0);
1999                     OUT_AS1 (page, %2);
2000                     OUT_AS1 (jmp, %2);
2001                     break;
2002                   }
2003                 else if (h == 0)
2004                   {
2005                     if (l == 1)
2006                       OUT_AS2 (dec, w, %L0);
2007                     else
2008                       {
2009                         OUT_AS2 (mov, w, %L0);
2010                         OUT_AS2 (sub, w, %L1);
2011                       }
2012                     OUT_AS2 (or, w, %H0);
2013                     OUT_AS1 (sz,);
2014                     OUT_AS1 (page, %2);
2015                     OUT_AS1 (jmp, %2);
2016                     break;
2017                   }
2018                 else if (l == 0)
2019                   {
2020                     if (h == 1)
2021                       OUT_AS2 (dec, w, %H0);
2022                     else
2023                       {
2024                         OUT_AS2 (mov, w, %H0);
2025                         OUT_AS2 (sub, w, %H1);
2026                       }
2027                     OUT_AS2 (or, w, %L0);
2028                     OUT_AS1 (sz,);
2029                     OUT_AS1 (page, %2);
2030                     OUT_AS1 (jmp, %2);
2031                     break;
2032                   }
2033               }
2034
2035             OUT_AS2 (mov, w, %H1);
2036             if (imm_cmp && (h == l))
2037               {
2038                 OUT_AS2 (csne, w, %H0);
2039                 OUT_AS2 (cse, w, %L0);
2040               }
2041             else
2042               {
2043                 OUT_AS2 (cse, w, %H0);
2044                 OUT_AS1 (page, %2);
2045                 OUT_AS1 (jmp, %2);
2046                 OUT_AS2 (mov, w, %L1);
2047                 OUT_AS2 (cse, w, %L0);
2048               }
2049             OUT_AS1 (page, %2);
2050             OUT_AS1 (jmp, %2);
2051           }
2052           break;
2053
2054         case GTU:
2055           if (imm_sub)
2056             {
2057               /* > 0xffff never succeeds!  */
2058               if ((INTVAL (operands[1]) & 0xffff) != 0xffff)
2059                 {
2060                   operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2061                   OUT_AS2 (mov, w, %L3);
2062                   OUT_AS2 (sub, w, %L0);
2063                   OUT_AS2 (mov, w, %H3);
2064                   OUT_AS2 (subc, w, %H0);
2065                   OUT_AS1 (snc,);
2066                   OUT_AS1 (page, %2);
2067                   OUT_AS1 (jmp, %2);
2068                 }
2069             }
2070           else
2071             {
2072               OUT_AS2 (mov, w, %L0);
2073               OUT_AS2 (sub, w, %L1);
2074               OUT_AS2 (mov, w, %H0);
2075               OUT_AS2 (subc, w, %H1);
2076               OUT_AS1 (sc,);
2077               OUT_AS1 (page, %2);
2078               OUT_AS1 (jmp, %2);
2079             }
2080           break;
2081
2082         case GEU:
2083           if (imm_sub)
2084             {
2085               if (INTVAL (operands[0]) == 0)
2086                 {
2087                   OUT_AS2 (mov, w, %H1);
2088                   OUT_AS2 (or, w, %L1);
2089                   OUT_AS1 (snz,);
2090                   OUT_AS1 (page, %2);
2091                   OUT_AS1 (jmp, %2);
2092                 }
2093               else
2094                 {
2095                   operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2096                   OUT_AS2 (mov, w, %L3);
2097                   OUT_AS2 (sub, w, %L1);
2098                   OUT_AS2 (mov, w, %H3);
2099                   OUT_AS2 (subc, w, %H1);
2100                   OUT_AS1 (sc,);
2101                   OUT_AS1 (page, %2);
2102                   OUT_AS1 (jmp, %2);
2103                 }
2104             }
2105           else
2106             {
2107               OUT_AS2 (mov, w, %L1);
2108               OUT_AS2 (sub, w, %L0);
2109               OUT_AS2 (mov, w, %H1);
2110               OUT_AS2 (subc, w, %H0);
2111               OUT_AS1 (snc,);
2112               OUT_AS1 (page, %2);
2113               OUT_AS1 (jmp, %2);
2114             }
2115           break;
2116
2117         case LTU:
2118           if (imm_sub)
2119             {
2120               if (INTVAL (operands[0]) == 0)
2121                 {
2122                   OUT_AS2 (mov, w, %H1);
2123                   OUT_AS2 (or, w, %L1);
2124                   OUT_AS1 (sz,);
2125                   OUT_AS1 (page, %2);
2126                   OUT_AS1 (jmp, %2);
2127                 }
2128               else
2129                 {
2130                   operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2131                   OUT_AS2 (mov, w, %L3);
2132                   OUT_AS2 (sub, w, %L1);
2133                   OUT_AS2 (mov, w, %H3);
2134                   OUT_AS2 (subc, w, %H1);
2135                   OUT_AS1 (snc,);
2136                   OUT_AS1 (page, %2);
2137                   OUT_AS1 (jmp, %2);
2138                 }
2139             }
2140           else
2141             {
2142               OUT_AS2 (mov, w, %L1);
2143               OUT_AS2 (sub, w, %L0);
2144               OUT_AS2 (mov, w, %H1);
2145               OUT_AS2 (subc, w, %H0);
2146               OUT_AS1 (sc,);
2147               OUT_AS1 (page, %2);
2148               OUT_AS1 (jmp, %2);
2149             }
2150           break;
2151
2152         case LEU:
2153           if (imm_sub)
2154             {
2155               if ((INTVAL (operands[1]) & 0xffff) == 0xffff)
2156                 {
2157                   /* <= 0xffff always succeeds.  */
2158                   OUT_AS1 (page, %2);
2159                   OUT_AS1 (jmp, %2);
2160                 }
2161               else
2162                 {
2163                   operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2164                   OUT_AS2 (mov, w, %L3);
2165                   OUT_AS2 (sub, w, %L0);
2166                   OUT_AS2 (mov, w, %H3);
2167                   OUT_AS2 (subc, w, %H0);
2168                   OUT_AS1 (sc,);
2169                   OUT_AS1 (page, %2);
2170                   OUT_AS1 (jmp, %2);
2171                 }
2172             }
2173           else
2174             {
2175               OUT_AS2 (mov, w, %L0);
2176               OUT_AS2 (sub, w, %L1);
2177               OUT_AS2 (mov, w, %H0);
2178               OUT_AS2 (subc, w, %H1);
2179               OUT_AS1 (snc,);
2180               OUT_AS1 (page, %2);
2181               OUT_AS1 (jmp, %2);
2182             }
2183           break;
2184
2185         default:
2186           abort ();
2187         }
2188       break;
2189
2190     case SImode:
2191       switch (code)
2192         {
2193         case EQ:
2194           {
2195             unsigned char a = 0, b = 1, c = 2, d = 3;
2196
2197             if (imm_cmp)
2198               {
2199                 a = (INTVAL (operands[1]) >> 24) & 0xff;
2200                 b = (INTVAL (operands[1]) >> 16) & 0xff;
2201                 c = (INTVAL (operands[1]) >> 8) & 0xff;
2202                 d = INTVAL (operands[1]) & 0xff;
2203               }
2204
2205             OUT_AS2 (mov, w, %A1);
2206             if (imm_cmp && (b == a))
2207               {
2208                 OUT_AS2 (csne, w, %A0);
2209                 OUT_AS2 (cse, w, %B0);
2210               }
2211             else
2212               {
2213                 OUT_AS2 (cse, w, %A0);
2214                 OUT_AS1 (page, 2f);
2215                 OUT_AS1 (jmp, 2f);
2216                 OUT_AS2 (mov, w, %B1);
2217                 OUT_AS2 (cse, w, %B0);
2218               }
2219             OUT_AS1 (page, 2f);
2220             OUT_AS1 (jmp, 2f);
2221             if (! imm_cmp || (c != b))
2222               OUT_AS2 (mov, w, %C1);
2223             OUT_AS2 (cse, w, %C0);
2224             OUT_AS1 (page, 2f);
2225             OUT_AS1 (jmp, 2f);
2226             if (! imm_cmp || (d != c))
2227               OUT_AS2 (mov, w, %D1);
2228             OUT_AS2 (csne, w, %D0);
2229             OUT_AS1 (page, %2);
2230             OUT_AS1 (jmp, %2);
2231             OUT_AS1 (2:,);
2232           }
2233           break;
2234
2235         case NE:
2236           {
2237             unsigned char a = 0, b = 1, c = 2, d = 3;
2238
2239             if (imm_cmp)
2240               {
2241                 a = (INTVAL (operands[1]) >> 24) & 0xff;
2242                 b = (INTVAL (operands[1]) >> 16) & 0xff;
2243                 c = (INTVAL (operands[1]) >> 8) & 0xff;
2244                 d = INTVAL (operands[1]) & 0xff;
2245               }
2246
2247             OUT_AS2 (mov, w, %A1);
2248             if (imm_cmp && (b == a))
2249               {
2250                 OUT_AS2 (csne, w, %A0);
2251                 OUT_AS2 (cse, w, %B0);
2252               }
2253             else
2254               {
2255                 OUT_AS2 (cse, w, %A0);
2256                 OUT_AS1 (page, %2);
2257                 OUT_AS1 (jmp, %2);
2258                 OUT_AS2 (mov, w, %B1);
2259                 OUT_AS2 (cse, w, %B0);
2260               }
2261             OUT_AS1 (page, %2);
2262             OUT_AS1 (jmp, %2);
2263             if (! imm_cmp || (c != b))
2264               OUT_AS2 (mov, w, %C1);
2265             if (imm_cmp && (d == c))
2266               {
2267                 OUT_AS2 (csne, w, %C0);
2268                 OUT_AS2 (cse, w, %D0);
2269               }
2270             else
2271               {
2272                 OUT_AS2 (cse, w, %C0);
2273                 OUT_AS1 (page, %2);
2274                 OUT_AS1 (jmp, %2);
2275                 OUT_AS2 (mov, w, %D1);
2276                 OUT_AS2 (cse, w, %D0);
2277               }
2278             OUT_AS1 (page, %2);
2279             OUT_AS1 (jmp, %2);
2280           }
2281           break;
2282
2283         case GTU:
2284           if (imm_sub)
2285             {
2286               /* > 0xffffffff never succeeds!  */
2287               if ((unsigned HOST_WIDE_INT)(INTVAL (operands[1]) & 0xffffffff)
2288                   != 0xffffffff)
2289                 {
2290                   operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2291                   OUT_AS2 (mov, w, %D3);
2292                   OUT_AS2 (sub, w, %D0);
2293                   OUT_AS2 (mov, w, %C3);
2294                   OUT_AS2 (subc, w, %C0);
2295                   OUT_AS2 (mov, w, %B3);
2296                   OUT_AS2 (subc, w, %B0);
2297                   OUT_AS2 (mov, w, %A3);
2298                   OUT_AS2 (subc, w, %A0);
2299                   OUT_AS1 (snc,);
2300                   OUT_AS1 (page, %2);
2301                   OUT_AS1 (jmp, %2);
2302                 }
2303             }
2304           else
2305             {
2306               OUT_AS2 (mov, w, %D0);
2307               OUT_AS2 (sub, w, %D1);
2308               OUT_AS2 (mov, w, %C0);
2309               OUT_AS2 (subc, w, %C1);
2310               OUT_AS2 (mov, w, %B0);
2311               OUT_AS2 (subc, w, %B1);
2312               OUT_AS2 (mov, w, %A0);
2313               OUT_AS2 (subc, w, %A1);
2314               OUT_AS1 (sc,);
2315               OUT_AS1 (page, %2);
2316               OUT_AS1 (jmp, %2);
2317             }
2318           break;
2319
2320         case GEU:
2321           if (imm_sub)
2322             {
2323               if (INTVAL (operands[0]) == 0)
2324                 {
2325                   OUT_AS2 (mov, w, %A1);
2326                   OUT_AS2 (or, w, %B1);
2327                   OUT_AS2 (or, w, %C1);
2328                   OUT_AS2 (or, w, %D1);
2329                   OUT_AS1 (snz,);
2330                   OUT_AS1 (page, %2);
2331                   OUT_AS1 (jmp, %2);
2332                 }
2333               else
2334                 {
2335                   operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2336                   OUT_AS2 (mov, w, %D3);
2337                   OUT_AS2 (sub, w, %D1);
2338                   OUT_AS2 (mov, w, %C3);
2339                   OUT_AS2 (subc, w, %C1);
2340                   OUT_AS2 (mov, w, %B3);
2341                   OUT_AS2 (subc, w, %B1);
2342                   OUT_AS2 (mov, w, %A3);
2343                   OUT_AS2 (subc, w, %A1);
2344                   OUT_AS1 (sc,);
2345                   OUT_AS1 (page, %2);
2346                   OUT_AS1 (jmp, %2);
2347                 }
2348             }
2349           else
2350             {
2351               OUT_AS2 (mov, w, %D1);
2352               OUT_AS2 (sub, w, %D0);
2353               OUT_AS2 (mov, w, %C1);
2354               OUT_AS2 (subc, w, %C0);
2355               OUT_AS2 (mov, w, %B1);
2356               OUT_AS2 (subc, w, %B0);
2357               OUT_AS2 (mov, w, %A1);
2358               OUT_AS2 (subc, w, %A0);
2359               OUT_AS1 (snc,);
2360               OUT_AS1 (page, %2);
2361               OUT_AS1 (jmp, %2);
2362             }
2363           break;
2364
2365         case LTU:
2366           if (imm_sub)
2367             {
2368               if (INTVAL (operands[0]) == 0)
2369                 {
2370                   OUT_AS2 (mov, w, %A1);
2371                   OUT_AS2 (or, w, %B1);
2372                   OUT_AS2 (or, w, %C1);
2373                   OUT_AS2 (or, w, %D1);
2374                   OUT_AS1 (sz,);
2375                   OUT_AS1 (page, %2);
2376                   OUT_AS1 (jmp, %2);
2377                 }
2378               else
2379                 {
2380                   operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2381                   OUT_AS2 (mov, w, %D3);
2382                   OUT_AS2 (sub, w, %D1);
2383                   OUT_AS2 (mov, w, %C3);
2384                   OUT_AS2 (subc, w, %C1);
2385                   OUT_AS2 (mov, w, %B3);
2386                   OUT_AS2 (subc, w, %B1);
2387                   OUT_AS2 (mov, w, %A3);
2388                   OUT_AS2 (subc, w, %A1);
2389                   OUT_AS1 (snc,);
2390                   OUT_AS1 (page, %2);
2391                   OUT_AS1 (jmp, %2);
2392                 }
2393             }
2394           else
2395             {
2396               OUT_AS2 (mov, w, %D1);
2397               OUT_AS2 (sub, w, %D0);
2398               OUT_AS2 (mov, w, %C1);
2399               OUT_AS2 (subc, w, %C0);
2400               OUT_AS2 (mov, w, %B1);
2401               OUT_AS2 (subc, w, %B0);
2402               OUT_AS2 (mov, w, %A1);
2403               OUT_AS2 (subc, w, %A0);
2404               OUT_AS1 (sc,);
2405               OUT_AS1 (page, %2);
2406               OUT_AS1 (jmp, %2);
2407             }
2408           break;
2409
2410         case LEU:
2411           if (imm_sub)
2412             {
2413               if ((unsigned HOST_WIDE_INT)(INTVAL (operands[1]) & 0xffffffff)
2414                   == 0xffffffff)
2415                 {
2416                   /* <= 0xffffffff always succeeds.  */
2417                   OUT_AS1 (page, %2);
2418                   OUT_AS1 (jmp, %2);
2419                 }
2420               else
2421                 {
2422                   operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2423                   OUT_AS2 (mov, w, %D3);
2424                   OUT_AS2 (sub, w, %D0);
2425                   OUT_AS2 (mov, w, %C3);
2426                   OUT_AS2 (subc, w, %C0);
2427                   OUT_AS2 (mov, w, %B3);
2428                   OUT_AS2 (subc, w, %B0);
2429                   OUT_AS2 (mov, w, %A3);
2430                   OUT_AS2 (subc, w, %A0);
2431                   OUT_AS1 (sc,);
2432                   OUT_AS1 (page, %2);
2433                   OUT_AS1 (jmp, %2);
2434                 }
2435             }
2436           else
2437             {
2438               OUT_AS2 (mov, w, %D0);
2439               OUT_AS2 (sub, w, %D1);
2440               OUT_AS2 (mov, w, %C0);
2441               OUT_AS2 (subc, w, %C1);
2442               OUT_AS2 (mov, w, %B0);
2443               OUT_AS2 (subc, w, %B1);
2444               OUT_AS2 (mov, w, %A0);
2445               OUT_AS2 (subc, w, %A1);
2446               OUT_AS1 (snc,);
2447               OUT_AS1 (page, %2);
2448               OUT_AS1 (jmp, %2);
2449             }
2450           break;
2451
2452         default:
2453           abort ();
2454         }
2455       break;
2456
2457     case DImode:
2458       if (GET_CODE (operands[1]) == CONST_INT)
2459         {
2460           const_low = INTVAL (operands[1]);
2461           const_high = (const_low >= 0) - 1;
2462         }
2463       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
2464         {
2465           const_low = CONST_DOUBLE_LOW (operands[1]);
2466           const_high = CONST_DOUBLE_HIGH (operands[1]);
2467         }
2468       switch (code)
2469         {
2470         case EQ:
2471           {
2472             unsigned char s = 0, t = 1, u = 2, v = 3;
2473             unsigned char w = 4, x = 5, y = 6, z = 7;
2474             if (optimize_size)
2475               {
2476                 if (GET_CODE (operands[0]) == MEM
2477                     && true_regnum (XEXP (operands[0], 0)) == REG_DP)
2478                   {
2479                     OUT_AS1 (push, %Z1%<);
2480                     OUT_AS1 (push, %Y1%<);
2481                     OUT_AS1 (push, %X1%<);
2482                     OUT_AS1 (push, %W1%<);
2483                     OUT_AS1 (push, %V1%<);
2484                     OUT_AS1 (push, %U1%<);
2485                     OUT_AS1 (push, %T1%<);
2486                     OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
2487                     OUT_AS1 (page, __cmpdi2_dp);
2488                     OUT_AS1 (call, __cmpdi2_dp);
2489                     OUT_AS2 (csne, w, #1);
2490                     OUT_AS1 (page, %2);
2491                     OUT_AS1 (jmp, %2);
2492                   }
2493                 else
2494                   {
2495                     OUT_AS1 (push, %Z1%<);
2496                     OUT_AS1 (push, %Y1%<);
2497                     OUT_AS1 (push, %X1%<);
2498                     OUT_AS1 (push, %W1%<);
2499                     OUT_AS1 (push, %V1%<);
2500                     OUT_AS1 (push, %U1%<);
2501                     OUT_AS1 (push, %T1%<);
2502                     OUT_AS1 (push, %S1%<);
2503                     OUT_AS1 (push, %Z0%<);
2504                     OUT_AS1 (push, %Y0%<);
2505                     OUT_AS1 (push, %X0%<);
2506                     OUT_AS1 (push, %W0%<);
2507                     OUT_AS1 (push, %V0%<);
2508                     OUT_AS1 (push, %U0%<);
2509                     OUT_AS1 (push, %T0%<);
2510                     OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
2511                     OUT_AS1 (page, __cmpdi2);
2512                     OUT_AS1 (call, __cmpdi2);
2513                     OUT_AS2 (csne, w, #1);
2514                     OUT_AS1 (page, %2);
2515                     OUT_AS1 (jmp, %2);
2516                   }
2517               }
2518             else
2519               {
2520                 if (imm_cmp)
2521                   {
2522                     s = (const_high >> 24) & 0xff;
2523                     t = (const_high >> 16) & 0xff;
2524                     u = (const_high >> 8) & 0xff;
2525                     v = const_high & 0xff;
2526                     w = (const_low >> 24) & 0xff;
2527                     x = (const_low >> 16) & 0xff;
2528                     y = (const_low >> 8) & 0xff;
2529                     z = const_low & 0xff;
2530                   }
2531
2532                 OUT_AS2 (mov, w, %S1);
2533                 if (imm_cmp && (s == t))
2534                   {
2535                     OUT_AS2 (csne, w, %S0);
2536                     OUT_AS2 (cse, w, %T0);
2537                   }
2538                 else
2539                   {
2540                     OUT_AS2 (cse, w, %S0);
2541                     OUT_AS1 (page, 2f);
2542                     OUT_AS1 (jmp, 2f);
2543                     OUT_AS2 (mov, w, %T1);
2544                     OUT_AS2 (cse, w, %T0);
2545                   }
2546                 OUT_AS1 (page, 2f);
2547                 OUT_AS1 (jmp, 2f);
2548
2549                 OUT_AS2 (mov, w, %U1);
2550                 if (imm_cmp && (u == v))
2551                   {
2552                     OUT_AS2 (csne, w, %U0);
2553                     OUT_AS2 (cse, w, %V0);
2554                   }
2555                 else
2556                   {
2557                     OUT_AS2 (cse, w, %U0);
2558                     OUT_AS1 (page, 2f);
2559                     OUT_AS1 (jmp, 2f);
2560                     OUT_AS2 (mov, w, %V1);
2561                     OUT_AS2 (cse, w, %V0);
2562                   }
2563                 OUT_AS1 (page, 2f);
2564                 OUT_AS1 (jmp, 2f);
2565
2566                 OUT_AS2 (mov, w, %W1);
2567                 if (imm_cmp && (w == x))
2568                   {
2569                     OUT_AS2 (csne, w, %W0);
2570                     OUT_AS2 (cse, w, %X0);
2571                   }
2572                 else
2573                   {
2574                     OUT_AS2 (cse, w, %W0);
2575                     OUT_AS1 (page, 2f);
2576                     OUT_AS1 (jmp, 2f);
2577                     OUT_AS2 (mov, w, %X1);
2578                     OUT_AS2 (cse, w, %X0);
2579                   }
2580                 OUT_AS1 (page, 2f);
2581                 OUT_AS1 (jmp, 2f);
2582
2583                 if (! imm_cmp || (x != y))
2584                   OUT_AS2 (mov, w, %Y1);
2585                 OUT_AS2 (cse, w, %Y0);
2586                 OUT_AS1 (page, 2f);
2587                 OUT_AS1 (jmp, 2f);
2588                 if (! imm_cmp || (z != y))
2589                   OUT_AS2 (mov, w, %Z1);
2590                 OUT_AS2 (csne, w, %Z0);
2591                 OUT_AS1 (page, %2);
2592                 OUT_AS1 (jmp, %2);
2593                 OUT_AS1 (2:,);
2594               }
2595           }
2596           break;
2597
2598         case NE:
2599           {
2600             unsigned char s = 0, t = 1, u = 2, v = 3;
2601             unsigned char w = 4, x = 5, y = 6, z = 7;
2602             
2603             if (optimize_size)
2604               {
2605                 if (GET_CODE (operands[0]) == MEM
2606                     && true_regnum (XEXP (operands[0], 0)) == REG_DP)
2607                   {
2608                     OUT_AS1 (push, %Z1%<);
2609                     OUT_AS1 (push, %Y1%<);
2610                     OUT_AS1 (push, %X1%<);
2611                     OUT_AS1 (push, %W1%<);
2612                     OUT_AS1 (push, %V1%<);
2613                     OUT_AS1 (push, %U1%<);
2614                     OUT_AS1 (push, %T1%<);
2615                     OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
2616                     OUT_AS1 (page, __cmpdi2_dp);
2617                     OUT_AS1 (call, __cmpdi2_dp);
2618                     OUT_AS2 (cse, w, #1);
2619                     OUT_AS1 (page, %2);
2620                     OUT_AS1 (jmp, %2);
2621                   }
2622                 else
2623                   {
2624                     OUT_AS1 (push, %Z1%<);
2625                     OUT_AS1 (push, %Y1%<);
2626                     OUT_AS1 (push, %X1%<);
2627                     OUT_AS1 (push, %W1%<);
2628                     OUT_AS1 (push, %V1%<);
2629                     OUT_AS1 (push, %U1%<);
2630                     OUT_AS1 (push, %T1%<);
2631                     OUT_AS1 (push, %S1%<);
2632                     OUT_AS1 (push, %Z0%<);
2633                     OUT_AS1 (push, %Y0%<);
2634                     OUT_AS1 (push, %X0%<);
2635                     OUT_AS1 (push, %W0%<);
2636                     OUT_AS1 (push, %V0%<);
2637                     OUT_AS1 (push, %U0%<);
2638                     OUT_AS1 (push, %T0%<);
2639                     OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
2640                     OUT_AS1 (page, __cmpdi2);
2641                     OUT_AS1 (call, __cmpdi2);
2642                     OUT_AS2 (cse, w, #1);
2643                     OUT_AS1 (page, %2);
2644                     OUT_AS1 (jmp, %2);
2645                   }
2646               }
2647             else
2648               {
2649                 if (imm_cmp)
2650                   {
2651                     s = (const_high >> 24) & 0xff;
2652                     t = (const_high >> 16) & 0xff;
2653                     u = (const_high >> 8) & 0xff;
2654                     v = const_high & 0xff;
2655                     w = (const_low >> 24) & 0xff;
2656                     x = (const_low >> 16) & 0xff;
2657                     y = (const_low >> 8) & 0xff;
2658                     z = const_low & 0xff;
2659                   }
2660
2661                 OUT_AS2 (mov, w, %S1);
2662                 if (imm_cmp && (s == t))
2663                   {
2664                     OUT_AS2 (csne, w, %S0);
2665                     OUT_AS2 (cse, w, %T0);
2666                   }
2667                 else
2668                   {
2669                     OUT_AS2 (cse, w, %S0);
2670                     OUT_AS1 (page, %2);
2671                     OUT_AS1 (jmp, %2);
2672                     OUT_AS2 (mov, w, %T1);
2673                     OUT_AS2 (cse, w, %T0);
2674                   }
2675                 OUT_AS1 (page, %2);
2676                 OUT_AS1 (jmp, %2);
2677
2678                 OUT_AS2 (mov, w, %U1);
2679                 if (imm_cmp && (u == v))
2680                   {
2681                     OUT_AS2 (csne, w, %U0);
2682                     OUT_AS2 (cse, w, %V0);
2683                   }
2684                 else
2685                   {
2686                     OUT_AS2 (cse, w, %U0);
2687                     OUT_AS1 (page, %2);
2688                     OUT_AS1 (jmp, %2);
2689                     OUT_AS2 (mov, w, %V1);
2690                     OUT_AS2 (cse, w, %V0);
2691                   }
2692                 OUT_AS1 (page, %2);
2693                 OUT_AS1 (jmp, %2);
2694
2695                 OUT_AS2 (mov, w, %W1);
2696                 if (imm_cmp && (w == x))
2697                   {
2698                     OUT_AS2 (csne, w, %W0);
2699                     OUT_AS2 (cse, w, %X0);
2700                   }
2701                 else
2702                   {
2703                     OUT_AS2 (cse, w, %W0);
2704                     OUT_AS1 (page, %2);
2705                     OUT_AS1 (jmp, %2);
2706                     OUT_AS2 (mov, w, %X1);
2707                     OUT_AS2 (cse, w, %X0);
2708                   }
2709                 OUT_AS1 (page, %2);
2710                 OUT_AS1 (jmp, %2);
2711
2712                 if (! imm_cmp || (y != x))
2713                   OUT_AS2 (mov, w, %Y1);
2714                 if (imm_cmp && (z == y))
2715                   {
2716                     OUT_AS2 (csne, w, %Y0);
2717                     OUT_AS2 (cse, w, %Z0);
2718                   }
2719                 else
2720                   {
2721                     OUT_AS2 (cse, w, %Y0);
2722                     OUT_AS1 (page, %2);
2723                     OUT_AS1 (jmp, %2);
2724                     OUT_AS2 (mov, w, %Z1);
2725                     OUT_AS2 (cse, w, %Z0);
2726                   }
2727                 OUT_AS1 (page, %2);
2728                 OUT_AS1 (jmp, %2);
2729               }
2730           }
2731           break;
2732
2733         case GTU:
2734           if (imm_sub)
2735             {
2736               /* > 0xffffffffffffffff never succeeds!  */
2737               if (((const_high & 0xffffffff) != 0xffffffff)
2738                   || ((const_low & 0xffffffff) != 0xffffffff))
2739                 {
2740                   operands[3] = GEN_INT (const_low + 1);
2741                   operands[4] = GEN_INT (const_high
2742                                          + (INTVAL (operands[3]) ? 0 : 1));
2743                   OUT_AS2 (mov, w, %D3);
2744                   OUT_AS2 (sub, w, %Z0);
2745                   OUT_AS2 (mov, w, %C3);
2746                   OUT_AS2 (subc, w, %Y0);
2747                   OUT_AS2 (mov, w, %B3);
2748                   OUT_AS2 (subc, w, %X0);
2749                   OUT_AS2 (mov, w, %A3);
2750                   OUT_AS2 (subc, w, %W0);
2751                   OUT_AS2 (mov, w, %D4);
2752                   OUT_AS2 (subc, w, %V0);
2753                   OUT_AS2 (mov, w, %C4);
2754                   OUT_AS2 (subc, w, %U0);
2755                   OUT_AS2 (mov, w, %B4);
2756                   OUT_AS2 (subc, w, %T0);
2757                   OUT_AS2 (mov, w, %A4);
2758                   OUT_AS2 (subc, w, %S0);
2759                   OUT_AS1 (snc,);
2760                   OUT_AS1 (page, %2);
2761                   OUT_AS1 (jmp, %2);
2762                 }
2763             }
2764           else
2765             {
2766               OUT_AS2 (mov, w, %Z0);
2767               OUT_AS2 (sub, w, %Z1);
2768               OUT_AS2 (mov, w, %Y0);
2769               OUT_AS2 (subc, w, %Y1);
2770               OUT_AS2 (mov, w, %X0);
2771               OUT_AS2 (subc, w, %X1);
2772               OUT_AS2 (mov, w, %W0);
2773               OUT_AS2 (subc, w, %W1);
2774               OUT_AS2 (mov, w, %V0);
2775               OUT_AS2 (subc, w, %V1);
2776               OUT_AS2 (mov, w, %U0);
2777               OUT_AS2 (subc, w, %U1);
2778               OUT_AS2 (mov, w, %T0);
2779               OUT_AS2 (subc, w, %T1);
2780               OUT_AS2 (mov, w, %S0);
2781               OUT_AS2 (subc, w, %S1);
2782               OUT_AS1 (sc,);
2783               OUT_AS1 (page, %2);
2784               OUT_AS1 (jmp, %2);
2785             }
2786           break;
2787
2788         case GEU:
2789           if (imm_sub)
2790             {
2791               HOST_WIDE_INT const_low0;
2792               HOST_WIDE_INT const_high0;
2793               
2794               if (GET_CODE (operands[0]) == CONST_INT)
2795                 {
2796                   const_low0 = INTVAL (operands[0]);
2797                   const_high0 = (const_low >= 0) - 1;
2798                 }
2799               else if (GET_CODE (operands[0]) == CONST_DOUBLE)
2800                 {
2801                   const_low0 = CONST_DOUBLE_LOW (operands[0]);
2802                   const_high0 = CONST_DOUBLE_HIGH (operands[0]);
2803                 }
2804               
2805               if (const_high0 == 0 && const_low0 == 0)
2806                 {
2807                   OUT_AS2 (mov, w, %S1);
2808                   OUT_AS2 (or, w, %T1);
2809                   OUT_AS2 (or, w, %U1);
2810                   OUT_AS2 (or, w, %V1);
2811                   OUT_AS2 (or, w, %W1);
2812                   OUT_AS2 (or, w, %X1);
2813                   OUT_AS2 (or, w, %Y1);
2814                   OUT_AS2 (or, w, %Z1);
2815                   OUT_AS1 (snz,);
2816                   OUT_AS1 (page, %2);
2817                   OUT_AS1 (jmp, %2);
2818                 }
2819               else
2820                 {
2821                   operands[3] = GEN_INT (const_low0 - 1);
2822                   operands[4] = GEN_INT (const_high0 - (const_low0 ? 1 : 0));
2823                   OUT_AS2 (mov, w, %D3);
2824                   OUT_AS2 (sub, w, %Z1);
2825                   OUT_AS2 (mov, w, %C3);
2826                   OUT_AS2 (subc, w, %Y1);
2827                   OUT_AS2 (mov, w, %B3);
2828                   OUT_AS2 (subc, w, %X1);
2829                   OUT_AS2 (mov, w, %A3);
2830                   OUT_AS2 (subc, w, %W1);
2831                   OUT_AS2 (mov, w, %D4);
2832                   OUT_AS2 (subc, w, %V1);
2833                   OUT_AS2 (mov, w, %C4);
2834                   OUT_AS2 (subc, w, %U1);
2835                   OUT_AS2 (mov, w, %B4);
2836                   OUT_AS2 (subc, w, %T1);
2837                   OUT_AS2 (mov, w, %A4);
2838                   OUT_AS2 (subc, w, %S1);
2839                   OUT_AS1 (sc,);
2840                   OUT_AS1 (page, %2);
2841                   OUT_AS1 (jmp, %2);
2842                 }
2843             }
2844           else
2845             {
2846               OUT_AS2 (mov, w, %Z1);
2847               OUT_AS2 (sub, w, %Z0);
2848               OUT_AS2 (mov, w, %Y1);
2849               OUT_AS2 (subc, w, %Y0);
2850               OUT_AS2 (mov, w, %X1);
2851               OUT_AS2 (subc, w, %X0);
2852               OUT_AS2 (mov, w, %W1);
2853               OUT_AS2 (subc, w, %W0);
2854               OUT_AS2 (mov, w, %V1);
2855               OUT_AS2 (subc, w, %V0);
2856               OUT_AS2 (mov, w, %U1);
2857               OUT_AS2 (subc, w, %U0);
2858               OUT_AS2 (mov, w, %T1);
2859               OUT_AS2 (subc, w, %T0);
2860               OUT_AS2 (mov, w, %S1);
2861               OUT_AS2 (subc, w, %S0);
2862               OUT_AS1 (snc,);
2863               OUT_AS1 (page, %2);
2864               OUT_AS1 (jmp, %2);
2865             }
2866           break;
2867
2868         case LTU:
2869           if (imm_sub)
2870             {
2871               HOST_WIDE_INT const_low0;
2872               HOST_WIDE_INT const_high0;
2873               
2874               if (GET_CODE (operands[0]) == CONST_INT)
2875                 {
2876                   const_low0 = INTVAL (operands[0]);
2877                   const_high0 = (const_low >= 0) - 1;
2878                 }
2879               else if (GET_CODE (operands[0]) == CONST_DOUBLE)
2880                 {
2881                   const_low0 = CONST_DOUBLE_LOW (operands[0]);
2882                   const_high0 = CONST_DOUBLE_HIGH (operands[0]);
2883                 }
2884               
2885               if (const_high0 == 0 && const_low0 == 0)
2886                 {
2887                   OUT_AS2 (mov, w, %S1);
2888                   OUT_AS2 (or, w, %T1);
2889                   OUT_AS2 (or, w, %U1);
2890                   OUT_AS2 (or, w, %V1);
2891                   OUT_AS2 (or, w, %W1);
2892                   OUT_AS2 (or, w, %X1);
2893                   OUT_AS2 (or, w, %Y1);
2894                   OUT_AS2 (or, w, %Z1);
2895                   OUT_AS1 (sz,);
2896                   OUT_AS1 (page, %2);
2897                   OUT_AS1 (jmp, %2);
2898                 }
2899               else
2900                 {
2901                   operands[3] = GEN_INT (const_low0 - 1);
2902                   operands[4] = GEN_INT (const_high0 - (const_low0 ? 1 : 0));
2903                   OUT_AS2 (mov, w, %D3);
2904                   OUT_AS2 (sub, w, %Z1);
2905                   OUT_AS2 (mov, w, %C3);
2906                   OUT_AS2 (subc, w, %Y1);
2907                   OUT_AS2 (mov, w, %B3);
2908                   OUT_AS2 (subc, w, %X1);
2909                   OUT_AS2 (mov, w, %A3);
2910                   OUT_AS2 (subc, w, %W1);
2911                   OUT_AS2 (mov, w, %D4);
2912                   OUT_AS2 (subc, w, %V1);
2913                   OUT_AS2 (mov, w, %C4);
2914                   OUT_AS2 (subc, w, %U1);
2915                   OUT_AS2 (mov, w, %B4);
2916                   OUT_AS2 (subc, w, %T1);
2917                   OUT_AS2 (mov, w, %A4);
2918                   OUT_AS2 (subc, w, %S1);
2919                   OUT_AS1 (snc,);
2920                   OUT_AS1 (page, %2);
2921                   OUT_AS1 (jmp, %2);
2922                 }
2923             }
2924           else
2925             {
2926               OUT_AS2 (mov, w, %Z1);
2927               OUT_AS2 (sub, w, %Z0);
2928               OUT_AS2 (mov, w, %Y1);
2929               OUT_AS2 (subc, w, %Y0);
2930               OUT_AS2 (mov, w, %X1);
2931               OUT_AS2 (subc, w, %X0);
2932               OUT_AS2 (mov, w, %W1);
2933               OUT_AS2 (subc, w, %W0);
2934               OUT_AS2 (mov, w, %V1);
2935               OUT_AS2 (subc, w, %V0);
2936               OUT_AS2 (mov, w, %U1);
2937               OUT_AS2 (subc, w, %U0);
2938               OUT_AS2 (mov, w, %T1);
2939               OUT_AS2 (subc, w, %T0);
2940               OUT_AS2 (mov, w, %S1);
2941               OUT_AS2 (subc, w, %S0);
2942               OUT_AS1 (sc,);
2943               OUT_AS1 (page, %2);
2944               OUT_AS1 (jmp, %2);
2945             }
2946           break;
2947
2948         case LEU:
2949           if (imm_sub)
2950             {
2951               if (((const_high & 0xffffffff) == 0xffffffff)
2952                   && ((const_low & 0xffffffff) == 0xffffffff))
2953                 {
2954                   /* <= 0xffffffffffffffff always succeeds.  */
2955                   OUT_AS1 (page, %2);
2956                   OUT_AS1 (jmp, %2);
2957                 }
2958               else
2959                 {
2960                   operands[3] = GEN_INT (const_low + 1);
2961                   operands[4] = GEN_INT (const_high
2962                                          + (INTVAL (operands[3]) ? 0 : 1));
2963                   OUT_AS2 (mov, w, %D3);
2964                   OUT_AS2 (sub, w, %Z0);
2965                   OUT_AS2 (mov, w, %C3);
2966                   OUT_AS2 (subc, w, %Y0);
2967                   OUT_AS2 (mov, w, %B3);
2968                   OUT_AS2 (subc, w, %X0);
2969                   OUT_AS2 (mov, w, %A3);
2970                   OUT_AS2 (subc, w, %W0);
2971                   OUT_AS2 (mov, w, %D4);
2972                   OUT_AS2 (subc, w, %V0);
2973                   OUT_AS2 (mov, w, %C4);
2974                   OUT_AS2 (subc, w, %U0);
2975                   OUT_AS2 (mov, w, %B4);
2976                   OUT_AS2 (subc, w, %T0);
2977                   OUT_AS2 (mov, w, %A4);
2978                   OUT_AS2 (subc, w, %S0);
2979                   OUT_AS1 (sc,);
2980                   OUT_AS1 (page, %2);
2981                   OUT_AS1 (jmp, %2);
2982                 }
2983             }
2984           else
2985             {
2986               OUT_AS2 (mov, w, %Z0);
2987               OUT_AS2 (sub, w, %Z1);
2988               OUT_AS2 (mov, w, %Y0);
2989               OUT_AS2 (subc, w, %Y1);
2990               OUT_AS2 (mov, w, %X0);
2991               OUT_AS2 (subc, w, %X1);
2992               OUT_AS2 (mov, w, %W0);
2993               OUT_AS2 (subc, w, %W1);
2994               OUT_AS2 (mov, w, %V0);
2995               OUT_AS2 (subc, w, %V1);
2996               OUT_AS2 (mov, w, %U0);
2997               OUT_AS2 (subc, w, %U1);
2998               OUT_AS2 (mov, w, %T0);
2999               OUT_AS2 (subc, w, %T1);
3000               OUT_AS2 (mov, w, %S0);
3001               OUT_AS2 (subc, w, %S1);
3002               OUT_AS1 (snc,);
3003               OUT_AS1 (page, %2);
3004               OUT_AS1 (jmp, %2);
3005             }
3006           break;
3007
3008         default:
3009           abort ();
3010         }
3011       break;
3012
3013     default:
3014       abort ();
3015   }
3016 #undef operands
3017   return "";
3018 }
3019
3020 /* Output rtx VALUE as .byte to file FILE.  */
3021
3022 void
3023 asm_output_char (FILE *file, rtx value)
3024 {
3025   fprintf (file, "\t.byte ");
3026   output_addr_const (file, value);
3027   fprintf (file, "\n");
3028 }
3029
3030
3031 /* Output VALUE as .byte to file FILE.  */
3032
3033 void
3034 asm_output_byte (FILE *file, int value)
3035 {
3036   fprintf (file, "\t.byte 0x%x\n",value & 0xff);
3037 }
3038
3039
3040 /* Output rtx VALUE as .word to file FILE.  */
3041
3042 void
3043 asm_output_short (FILE *file, rtx value)
3044 {
3045   fprintf (file, "\t.word ");
3046   output_addr_const (file, (value));
3047   fprintf (file, "\n");
3048 }
3049
3050
3051 /* Output real N to file FILE.  */
3052
3053 void
3054 asm_output_float (FILE *file, REAL_VALUE_TYPE n)
3055 {
3056   long val;
3057   char dstr[100];
3058   
3059   REAL_VALUE_TO_TARGET_SINGLE (n, val);
3060   real_to_decimal (dstr, &n, sizeof (dstr), 0, 1);
3061
3062   fprintf (file, "\t.long 0x%08lx\t/* %s */\n", val, dstr);
3063 }
3064
3065 /* Sets section name for declaration DECL.  */
3066   
3067 void
3068 unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
3069 {
3070   int len;
3071   const char *name;
3072   char *string;
3073   const char *prefix;
3074   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
3075   /* Strip off any encoding in name.  */
3076   name = (* targetm.strip_name_encoding) (name);
3077
3078   if (TREE_CODE (decl) == FUNCTION_DECL)
3079     {
3080       if (flag_function_sections)
3081         prefix = ".text.";
3082       else
3083         prefix = ".text";
3084     }
3085   else 
3086     abort ();
3087
3088   if (flag_function_sections)
3089     {
3090       len = strlen (name) + strlen (prefix);
3091       string = alloca (len + 1);
3092       sprintf (string, "%s%s", prefix, name);
3093       DECL_SECTION_NAME (decl) = build_string (len, string);
3094     }
3095 }
3096
3097 /* Return value is nonzero if pseudos that have been
3098    assigned to registers of class CLASS would likely be spilled
3099    because registers of CLASS are needed for spill registers.  */
3100
3101 enum reg_class
3102 class_likely_spilled_p (int c)
3103 {
3104   return (c == IP_REGS
3105           || c == IPL_REGS
3106           || c == IPH_REGS
3107           || c == DP_SP_REGS
3108           || c == SP_REGS
3109           || c == DP_REGS
3110           || c == DPL_REGS
3111           || c == DPH_REGS
3112           || c == PTR_REGS);
3113 }
3114
3115 /* Valid attributes:
3116    progmem - put data to program memory;
3117    naked     - don't generate function prologue/epilogue and `ret' command.
3118
3119    Only `progmem' attribute valid for type.  */
3120
3121 const struct attribute_spec ip2k_attribute_table[] =
3122 {
3123   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
3124   { "progmem",   0, 0, false, false, false,  ip2k_handle_progmem_attribute },
3125   { "naked",     0, 0, true,  false, false,  ip2k_handle_fndecl_attribute },
3126   { NULL,        0, 0, false, false, false, NULL }
3127 };
3128
3129 /* Handle a "progmem" attribute; arguments as in
3130    struct attribute_spec.handler.  */
3131 static tree
3132 ip2k_handle_progmem_attribute (tree *node, tree name,
3133                                tree args ATTRIBUTE_UNUSED,
3134                                int flags ATTRIBUTE_UNUSED,
3135                                bool *no_add_attrs)
3136 {
3137   if (DECL_P (*node))
3138     {
3139       if (TREE_CODE (*node) == TYPE_DECL)
3140         {
3141           /* This is really a decl attribute, not a type attribute,
3142              but try to handle it for GCC 3.0 backwards compatibility.  */
3143
3144           tree type = TREE_TYPE (*node);
3145           tree attr = tree_cons (name, args, TYPE_ATTRIBUTES (type));
3146           tree newtype = build_type_attribute_variant (type, attr);
3147
3148           TYPE_MAIN_VARIANT (newtype) = TYPE_MAIN_VARIANT (type);
3149           TREE_TYPE (*node) = newtype;
3150           *no_add_attrs = true;
3151         }
3152       else if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
3153         {
3154           if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node))
3155             {
3156               warning ("only initialized variables can be placed into "
3157                        "program memory area");
3158               *no_add_attrs = true;
3159             }
3160         }
3161       else
3162         {
3163           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
3164           *no_add_attrs = true;
3165         }
3166     }
3167
3168   return NULL_TREE;
3169 }
3170
3171 /* Handle an attribute requiring a FUNCTION_DECL; arguments as in
3172    struct attribute_spec.handler.  */
3173 static tree
3174 ip2k_handle_fndecl_attribute (tree *node, tree name,
3175                               tree args ATTRIBUTE_UNUSED,
3176                               int flags ATTRIBUTE_UNUSED,
3177                               bool *no_add_attrs)
3178 {
3179   if (TREE_CODE (*node) != FUNCTION_DECL)
3180     {
3181       warning ("`%s' attribute only applies to functions",
3182                IDENTIFIER_POINTER (name));
3183       *no_add_attrs = true;
3184     }
3185
3186   return NULL_TREE;
3187 }
3188
3189 /* Cost functions.  */
3190
3191 /* Compute a (partial) cost for rtx X.  Return true if the complete
3192    cost has been computed, and false if subexpressions should be
3193    scanned.  In either case, *TOTAL contains the cost result.  */
3194
3195 static bool
3196 ip2k_rtx_costs (rtx x, int code, int outer_code, int *total)
3197 {
3198   enum machine_mode mode = GET_MODE (x);
3199   int extra_cost = 0;
3200
3201   switch (code)
3202     {
3203     case CONST_INT:
3204     case CONST_DOUBLE:
3205     case LABEL_REF:
3206       *total = 0;
3207       return true;
3208     case CONST:
3209     case SYMBOL_REF:
3210       *total = 8;
3211       return true;
3212
3213     case MEM:
3214       *total = ip2k_address_cost (XEXP (x, 0));
3215       return true;
3216
3217     case ROTATE:
3218     case ROTATERT:
3219     case ASHIFT:
3220     case LSHIFTRT:
3221     case ASHIFTRT:
3222       if (GET_CODE (XEXP (x, 1)) == CONST_INT)
3223         {
3224           int val = INTVAL (XEXP (x, 1));
3225           int cost;
3226
3227           /* Shift by const instructions are proportional to
3228              the shift count modulus 8.  Note that we increase the mode
3229              size multiplier by 1 to account for clearing the carry flag.  */
3230           cost = COSTS_N_INSNS (abs (val) % 8);
3231           cost += rtx_cost (XEXP (x, 0), code);
3232           cost *= (GET_MODE_SIZE (mode) + 1);
3233
3234           /* Sign-preserving shifts require 2 extra instructions.  */
3235           if (code == ASHIFT)
3236             cost += COSTS_N_INSNS (2);
3237
3238           *total = cost;
3239           return true;
3240         }
3241       *total = rtx_cost (XEXP (x, 0), code);
3242       *total += COSTS_N_INSNS (GET_MODE_SIZE (mode) * 8);
3243       return true;
3244
3245     case MINUS:
3246     case PLUS:
3247     case AND:
3248     case XOR:
3249     case IOR:
3250       *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) * 3);
3251       return false;
3252
3253     case MOD:
3254     case DIV:
3255       if (mode == QImode)
3256         *total = COSTS_N_INSNS (20);
3257       else if (mode == HImode)
3258         *total = COSTS_N_INSNS (60);
3259       else if (mode == SImode)
3260         *total = COSTS_N_INSNS (180);
3261       else
3262         *total = COSTS_N_INSNS (540);
3263       return true;
3264
3265     case MULT:
3266       /* These costs are OK, but should really handle subtle cases
3267          where we're using sign or zero extended args as these are
3268          *much* cheaper than those given below!  */
3269       if (mode == QImode)
3270         *total = COSTS_N_INSNS (4);
3271       else if (mode == HImode)
3272         *total = COSTS_N_INSNS (12);
3273       else if (mode == SImode)
3274         *total = COSTS_N_INSNS (36);
3275       else
3276         *total = COSTS_N_INSNS (108);
3277       return true;
3278
3279     case NEG:
3280     case SIGN_EXTEND:
3281       extra_cost = COSTS_N_INSNS (GET_MODE_SIZE (mode));
3282       
3283       /* Fall through.  */
3284     case NOT:
3285     case COMPARE:
3286     case ABS:
3287       *total = extra_cost + COSTS_N_INSNS (GET_MODE_SIZE (mode) * 2);
3288       return false;
3289
3290     case TRUNCATE:
3291     case ZERO_EXTEND:
3292       if (outer_code == SET)
3293         {
3294           *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) * 3 / 2);
3295           return false;
3296         }
3297       else
3298         {
3299           *total = -(COSTS_N_INSNS (GET_MODE_SIZE (mode)) / 2);
3300           return true;
3301         }
3302
3303     case IF_THEN_ELSE:
3304       *total = rtx_cost (XEXP (x, 0), code) + COSTS_N_INSNS (2);
3305       return true;
3306
3307     case EQ:
3308     case NE:
3309     case LTU:
3310     case GTU:
3311     case LEU:
3312     case GEU:
3313     case LT:
3314     case GT:
3315     case LE:
3316     case GE:
3317       *total = 0;
3318       return false;
3319
3320     default:
3321       *total = COSTS_N_INSNS (4);
3322       return true;
3323     }
3324 }
3325
3326 /* Calculate the cost of a memory address.  */
3327
3328 static int
3329 ip2k_address_cost (rtx x)
3330 {
3331   switch (legitimate_address_p (VOIDmode, x, 0))
3332     {
3333     case 'S':                   /* Very low cost - (IP), (SP+N) or (DP+N)  */
3334       return 8;
3335       
3336     case 'R':                   /* Indirected through IP.  */
3337       return 8;
3338
3339     case 'L':                   /* Label references.  */
3340       return 0;
3341       
3342     case 'C':                   /* Constants and symbol references.  */
3343       return 4;
3344
3345     default:
3346       return 1000;              /* Must reload.  */
3347     }
3348 }
3349
3350 /* As part of the machine-dependent reorg we look for opcode sequences where
3351    we do some operation and then move the results back to one of the original
3352    source operands.  With working on the source operand directly is probably
3353    much cheaper and the move from this to the original source operand will be
3354    no more expensive than the original move.  */
3355
3356 #ifdef IP2K_MD_REORG_PASS
3357 static void
3358 mdr_resequence_xy_yx (first_insn)
3359      rtx first_insn;
3360 {
3361   rtx insn;
3362
3363   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3364     {
3365       rtx set;
3366
3367       if (GET_CODE (insn) != INSN)
3368         continue;
3369
3370       set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
3371       if (set == NULL_RTX)
3372         continue;
3373
3374       /* Look for operations that tend to be very cheap to run when the source
3375        * and dest args are the same because the IP2022 has opcodes that can
3376          operate on the source directly.  If we have to spill through the W
3377          register then we've possibly not got a good case for doing this.  */
3378       if ((GET_CODE (XEXP (set, 0)) == REG
3379            || GET_CODE (XEXP (set, 0)) == MEM)
3380           && (GET_CODE (XEXP (set, 1)) == ASHIFT
3381               || GET_CODE (XEXP (set, 1)) == ASHIFTRT
3382               || GET_CODE (XEXP (set, 1)) == LSHIFTRT
3383               || GET_CODE (XEXP (set, 1)) == XOR
3384               || GET_CODE (XEXP (set, 1)) == IOR
3385               || GET_CODE (XEXP (set, 1)) == AND
3386               || GET_CODE (XEXP (set, 1)) == PLUS
3387               || GET_CODE (XEXP (set, 1)) == MINUS
3388               || GET_CODE (XEXP (set, 1)) == MULT))
3389         {
3390           rtx set2;
3391           rtx next_insn;
3392
3393           next_insn = next_nonnote_insn (insn);
3394           if (! next_insn)
3395             continue;
3396
3397           if (GET_CODE (next_insn) != INSN)
3398             continue;
3399
3400           set2 = ((GET_CODE (PATTERN (next_insn)) == SET)
3401                   ? PATTERN (next_insn) : NULL_RTX);
3402           if (set2 == NULL_RTX)
3403             continue;
3404
3405           if ((GET_CODE (XEXP (XEXP (set, 1), 0)) == REG
3406                || GET_CODE (XEXP (XEXP (set, 1), 0)) == MEM)
3407               && rtx_equal_p (XEXP (set2, 0), XEXP (XEXP (set, 1), 0))
3408               && rtx_equal_p (XEXP (set2, 1), XEXP (set, 0)))
3409             {
3410               rtx next2_insn;
3411               rtx b_insn;
3412
3413               b_insn = gen_rtx_SET (VOIDmode,
3414                                     XEXP (XEXP (set, 1), 0),
3415                                     gen_rtx_fmt_ee (GET_CODE (XEXP (set, 1)),
3416                                                     GET_MODE (XEXP (set, 0)),
3417                                                     XEXP (XEXP (set, 1), 0),
3418                                                     XEXP (XEXP (set, 1), 1)));
3419                 
3420               emit_insn_before (b_insn, insn);
3421               b_insn = gen_rtx_SET (GET_MODE (XEXP (set, 0)), XEXP (set, 0),
3422                                     XEXP (XEXP (set, 1), 0));
3423               next2_insn = emit_insn_before (b_insn, insn);
3424               delete_insn (insn);
3425               delete_insn (next_insn);
3426               insn = next2_insn;
3427               continue;
3428             }
3429
3430           /* Having tried with one operand of the expression, now, if
3431              appropriate, try to do the same thing with the second operand.
3432              Of course there are fewer operations that can match here
3433              because they must be commutative.  */
3434           if (GET_RTX_CLASS (GET_CODE (XEXP (set, 1))) == RTX_COMM_ARITH
3435               && (GET_CODE (XEXP (XEXP (set, 1), 1)) == REG
3436                   || GET_CODE (XEXP (XEXP (set, 1), 1)) == MEM)
3437               && rtx_equal_p (XEXP (set2, 0), XEXP (XEXP (set, 1), 1))
3438               && rtx_equal_p (XEXP (set2, 1), XEXP (set, 0)))
3439             {
3440               rtx rtx_ee;
3441               rtx next2_insn;
3442               int swap_args;
3443
3444               /* Try to ensure that we put things in a canonical form.  */
3445               swap_args = (GET_CODE (XEXP (XEXP (set, 1), 0)) == REG
3446                            || GET_CODE (XEXP (XEXP (set, 1), 0)) == MEM);
3447               rtx_ee = gen_rtx_fmt_ee (GET_CODE (XEXP (set, 1)),
3448                                        GET_MODE (XEXP (set, 0)),
3449                                        XEXP (XEXP (set, 1), swap_args ? 1 : 0),
3450                                        XEXP (XEXP (set, 1),
3451                                              swap_args ? 0 : 1));
3452               
3453               emit_insn_before (gen_rtx_SET (VOIDmode,
3454                                              XEXP (XEXP (set, 1), 1),
3455                                              rtx_ee),
3456                                 insn);
3457               next2_insn = emit_insn_before (gen_rtx_SET
3458                                              (GET_MODE (XEXP (set, 0)),
3459                                               XEXP (set, 0),
3460                                               XEXP (XEXP (set, 1), 1)),
3461                                              insn);
3462               delete_insn (insn);
3463               delete_insn (next_insn);
3464               insn = next2_insn;
3465             }
3466         }
3467     }
3468 }
3469
3470 /* Replace and recurse until we've tried QImode pieces!  */
3471
3472 static void
3473 mdr_pres_replace_and_recurse (orig, with, insn)
3474      rtx orig;
3475      rtx with;
3476      rtx insn;
3477 {
3478   enum machine_mode new_mode;
3479
3480   validate_replace_rtx (orig, with, insn);
3481
3482   switch (GET_MODE (orig))
3483     {
3484     case DImode:
3485     case DFmode:
3486       new_mode = SImode;
3487       break;
3488
3489     case SImode:
3490     case SFmode:
3491       new_mode = HImode;
3492       break;
3493
3494     case HImode:
3495       new_mode = QImode;
3496       break;
3497
3498     default:
3499       return;
3500     }
3501
3502   mdr_pres_replace_and_recurse (ip2k_get_low_half (orig, new_mode),
3503                                 ip2k_get_low_half (with, new_mode),
3504                                 insn);
3505   mdr_pres_replace_and_recurse (ip2k_get_high_half (orig, new_mode),
3506                                 ip2k_get_high_half (with, new_mode),
3507                                 insn);
3508 }
3509
3510 /* Assist the following function, mdr_propagate_reg_equivs().  */
3511
3512 static void
3513 mdr_propagate_reg_equivs_sequence (first_insn, orig, equiv)
3514      rtx first_insn;
3515      rtx orig;
3516      rtx equiv;
3517 {
3518   rtx try_insn;
3519   rtx try_equiv = equiv;
3520
3521   /* First scan the RTL looking for anything else that might clobber what
3522      we're doing.  If we find anything then we can't do the replacement.  */
3523   for (try_insn = next_nonnote_insn (first_insn);
3524        try_insn; try_insn = next_nonnote_insn (try_insn))
3525     {
3526       rtx pattern;
3527
3528       if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
3529         continue;
3530
3531       pattern = PATTERN (try_insn);
3532       if (GET_CODE (pattern) == PARALLEL)
3533         {
3534           int j;
3535
3536           for (j = 0; j < XVECLEN (pattern, 0); j++)
3537             {
3538               rtx px = XVECEXP (pattern, 0, j);
3539
3540               if (GET_CODE (px) == SET)
3541                 if (! ip2k_composite_xexp_not_uses_reg_p (XEXP (px, 0),
3542                                                           REGNO (orig),
3543                                                           GET_MODE_SIZE (GET_MODE (orig))))
3544                   return;
3545             }
3546         }
3547       else if (GET_CODE (pattern) == SET)
3548         {
3549           if (! ip2k_composite_xexp_not_uses_reg_p (XEXP (pattern, 0),
3550                                                     REGNO (orig),
3551                                                     GET_MODE_SIZE (GET_MODE (orig))))
3552             return;
3553         }
3554     }
3555
3556   /* Once we've decided that we're safe to do the replacement then make the
3557      changes.  */
3558   for (try_insn = next_nonnote_insn (first_insn); try_insn;
3559        try_insn = next_nonnote_insn (try_insn))
3560     {
3561       rtx set;
3562       rtx new_equiv = NULL_RTX;
3563
3564       if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
3565         {
3566           try_equiv = equiv;
3567           continue;
3568         }
3569
3570       set = ((GET_CODE (PATTERN (try_insn)) == SET)
3571              ? PATTERN (try_insn) : NULL_RTX);
3572       if (set == NULL_RTX)
3573         continue;
3574
3575       /* We look for a special case of "push" operations screwing our
3576          register equivalence when it's based on a stack slot.  We can
3577          track this one and replace the old equivalence expression with
3578          a new one.  */
3579       if (GET_CODE (XEXP (set, 0)) == MEM
3580           && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
3581           && REG_P (XEXP (XEXP (XEXP (set, 0), 0), 0))
3582           && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP)
3583         {
3584           /* XXX - need to ensure that we can track this without going
3585              out of range!  */
3586           HOST_WIDE_INT disp = (INTVAL (XEXP (XEXP (try_equiv, 0), 1))
3587                                + GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
3588           new_equiv = gen_rtx_MEM (GET_MODE (try_equiv),
3589                                    gen_rtx_PLUS (Pmode,
3590                                                  gen_rtx_REG (HImode, REG_SP),
3591                                                  GEN_INT (disp)));
3592         }
3593
3594       /* The replacement process is somewhat complicated by the fact that we
3595          might be dealing with what were originally subregs and thus we have
3596          to replace parts of our original expression!  */
3597       mdr_pres_replace_and_recurse (orig, try_equiv, try_insn);
3598
3599       if (new_equiv != NULL_RTX)
3600         try_equiv = new_equiv;
3601     }
3602 }
3603
3604 /* Try propagating register equivalences forwards.  It may be that we can
3605    replace a register use with an equivalent expression that already
3606    holds the same value and thus allow one or more register loads to
3607    be eliminated.  */
3608
3609 static void
3610 mdr_propagate_reg_equivs (first_insn)
3611      rtx first_insn;
3612 {
3613   rtx insn;
3614   rtx set;
3615
3616   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3617     {
3618       if (GET_CODE (insn) != INSN)
3619         continue;
3620
3621       set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
3622       if (set == NULL_RTX)
3623         continue;
3624
3625       /* Have we found a stack slot equivalence for a register?  */
3626       if (REG_P (XEXP (set, 0))
3627           && REGNO (XEXP (set, 0)) >= 0x88
3628           && GET_CODE (XEXP (set, 1)) == MEM
3629           && GET_CODE (XEXP (XEXP (set, 1), 0)) == PLUS
3630           && REG_P (XEXP (XEXP (XEXP (set, 1), 0), 0))
3631           && REGNO (XEXP (XEXP (XEXP (set, 1), 0), 0)) == REG_SP
3632           && find_reg_note (insn, REG_EQUIV, NULL_RTX))
3633         {
3634           mdr_propagate_reg_equivs_sequence (insn, XEXP (set, 0),
3635                                              XEXP (set, 1));
3636         }
3637     }
3638 }
3639
3640 /* Structure used to track jump targets.  */
3641
3642 struct dpre_jump_targets
3643 {
3644   int target;                   /* Is this a jump target?  */
3645   int reach_count;              /* Number of ways we can reach this insn.  */
3646   int touch_count;              /* Number of times we've touched this
3647                                    insns during scanning.  */
3648   rtx dp_equiv;                 /* DP-equivalence at this point.  */
3649 };
3650
3651 struct dpre_jump_targets *ip2k_dpre_jump_targets;
3652
3653 /* DP equivalence tracking used within DP reload elimination.  */
3654
3655 static int
3656 track_dp_reload (insn, dp_current, dp_current_ok, modifying)
3657      rtx insn;
3658      rtx *dp_current;
3659      int dp_current_ok;
3660      int modifying;
3661 {
3662   rtx set;
3663
3664   if (GET_CODE (insn) != INSN)
3665     {
3666       *dp_current = NULL_RTX;
3667       return 1;
3668     }
3669
3670   set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
3671   if (set == NULL_RTX)
3672     {
3673       *dp_current = NULL_RTX;
3674       return 1;
3675     }
3676
3677   /* If we're pushing a PLUS or MINUS then it's a win if we can replace
3678      an expression for which DP is equivalent with DP.  This happens
3679      surprisingly often when we pass a pointer to a structure embedded
3680      within another structure.  */
3681   if (*dp_current != NULL_RTX
3682       && GET_CODE (XEXP (set, 0)) == MEM
3683       && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
3684       && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
3685       && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
3686       && (GET_CODE (XEXP (set, 1)) == PLUS
3687           || GET_CODE (XEXP (set, 1)) == MINUS)
3688       && GET_CODE (*dp_current) != SYMBOL_REF
3689       && GET_CODE (*dp_current) != LABEL_REF
3690       && GET_CODE (*dp_current) != CONST)
3691     {
3692       if (modifying)
3693         validate_replace_rtx (*dp_current, gen_rtx_REG (HImode, REG_DP), insn);
3694     }
3695
3696   /* Look for DP being modified.  If it is, see if it's being changed
3697      to what it already is!  */
3698   if (GET_CODE (XEXP (set, 0)) == REG
3699       && REGNO (XEXP (set, 0)) == REG_DP
3700       && GET_MODE (XEXP (set, 0)) == HImode)
3701     {
3702       /* If this is an equivalence we can delete the new set operation.  */
3703       if (*dp_current != NULL_RTX
3704           && rtx_equal_p (XEXP (set, 1), *dp_current))
3705         {
3706           if (modifying)
3707             delete_insn (insn);
3708         }
3709       else
3710         {
3711           /* If we've not found an equivalence we can look for a special
3712              case where an operand of the expression that sets DP is
3713              already equivalent to DP and in that circumstance we simplify
3714              by replacing that expression with DP.  */
3715           if (*dp_current != NULL_RTX
3716               && GET_CODE (*dp_current) != SYMBOL_REF
3717               && GET_CODE (*dp_current) != LABEL_REF
3718               && GET_CODE (*dp_current) != CONST
3719               && modifying)
3720             validate_replace_rtx (*dp_current, XEXP (set, 0), insn);
3721
3722           /* Assuming that we're not loading DP from something that uses DP
3723              itself then we mark the new equivalence for DP.  If we did match
3724              DP then we can't re-use this one.  */
3725           if (ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_DP, 2))
3726             {
3727               *dp_current = XEXP (set, 1);
3728               return 1;
3729             }
3730           else
3731             {
3732               *dp_current = NULL_RTX;
3733               return 1;
3734             }
3735         }
3736     }
3737   else if (GET_CODE (XEXP (set, 0)) == REG
3738            && (REGNO (XEXP (set, 0)) == REG_DPL
3739                || REGNO (XEXP (set, 0)) == REG_DPH))
3740     {
3741       /* If we clobber part of DP then we've clobbered any equivalences!  */
3742       *dp_current = NULL_RTX;
3743       return 1;
3744     }
3745   else if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2)
3746            && *dp_current != NULL_RTX
3747            && !ip2k_xexp_not_uses_reg_p (*dp_current, REG_SP, 2))
3748     {
3749       /* We look for a special case of "push" operations screwing up the
3750          setting of DP when it's based on the stack.  We can track this one
3751          and replace the old expression for DP with a new one.  */
3752       if (GET_CODE (XEXP (set, 0)) == MEM
3753           && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
3754           && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
3755           && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
3756           && GET_CODE (*dp_current) == MEM
3757           && GET_CODE (XEXP (*dp_current, 0)) == PLUS)
3758         {
3759           /* XXX - need to ensure that we can track this without going
3760              out of range!   */
3761           HOST_WIDE_INT disp = (INTVAL (XEXP (XEXP (*dp_current, 0), 1))
3762                                 + GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
3763           *dp_current = gen_rtx_MEM (HImode,
3764                                      gen_rtx_PLUS (Pmode,
3765                                                    gen_rtx_REG (HImode, REG_SP),
3766                                                    GEN_INT (disp)));
3767           return 1;
3768         }
3769
3770       /* Now we look for writes to the stack.  We can determine if these will
3771          affect the equivalence we're tracking for DP and if not then we can
3772          keep tracking it.  */
3773       if (GET_CODE (XEXP (set, 0)) == MEM
3774           && GET_CODE (*dp_current) == MEM)
3775         {
3776           /* Look at the SP offsets and look for any overlaps.  */
3777           int dp_cur_sp_offs = INTVAL (XEXP (XEXP (*dp_current, 0), 1));
3778           int set_sp_offs = INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1));
3779
3780           if (abs (dp_cur_sp_offs - set_sp_offs) < 2)
3781             {
3782               *dp_current = NULL_RTX;
3783               return 1;
3784             }
3785         }
3786     }
3787   else if (GET_CODE (XEXP (set, 0)) == REG
3788            && *dp_current != NULL_RTX
3789            && !ip2k_xexp_not_uses_reg_p (*dp_current, REGNO (XEXP (set, 0)),
3790                                          GET_MODE_SIZE (GET_MODE (XEXP (set,
3791                                                                         0)))))
3792     {
3793       /* If we've just clobbered all or part of a register reference that we
3794          were sharing for DP then we can't share it any more!  */
3795       *dp_current = NULL_RTX;
3796     }
3797
3798   return dp_current_ok;
3799 }
3800
3801 /* As part of the machine-dependent reorg we scan loads and reloads of
3802    DP to see where any are redundant.  This does happens because we
3803    are able to subsequently transform things in interesting ways.  Sometimes
3804    gcc also does unnecessary reloads too so we try to eliminate these too.  */
3805
3806 static void
3807 mdr_try_dp_reload_elim (first_insn)
3808      rtx first_insn;
3809 {
3810   rtx insn;
3811   struct dpre_jump_targets *djt;
3812   rtx dp_current;
3813   int incomplete_scan;
3814   int last_incomplete_scan;
3815
3816   ip2k_dpre_jump_targets
3817     = (struct dpre_jump_targets *) xcalloc (get_max_uid (),
3818                                             sizeof (struct dpre_jump_targets));
3819
3820   /* First we scan to build up a list of all CODE_LABEL insns and we work out
3821      how many different ways we can reach them.  */
3822   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3823     {
3824       if (GET_CODE (insn) == CODE_LABEL)
3825         {
3826           djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
3827           djt->target = 1;
3828           djt->reach_count = LABEL_NUSES (insn);
3829           djt->touch_count = 0;
3830           djt->dp_equiv = NULL_RTX;
3831           if (! prev_nonnote_insn (insn)
3832               || (prev_nonnote_insn (insn)
3833                   && GET_CODE (prev_nonnote_insn (insn)) != BARRIER))
3834             djt->reach_count++;
3835         }
3836     }
3837
3838   /* Next we scan all of the ways of reaching the code labels to see
3839      what the DP register is equivalent to as we reach them.  If we find
3840      that they're the same then we keep noting the matched value.  We
3841      iterate around this until we reach a convergence on DP equivalences
3842      at all code labels - we have to be very careful not to be too
3843      optimistic!  */
3844   incomplete_scan = -1;
3845   do
3846     {
3847       int dp_current_ok = 0;
3848       last_incomplete_scan = incomplete_scan;
3849       dp_current = NULL_RTX;
3850
3851       for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3852         {
3853           /* If we have a code label then we need to see if we already know
3854              what the equivalence is at this point.  If we do then we use it
3855              immediately, but if we don't then we have a special case to track
3856              when we hit a fallthrough-edge (label with no barrier preceding
3857              it).  Any other accesses to the label must be from jump insns
3858              and so they're handled elsewhere.  */
3859           if (GET_CODE (insn) == CODE_LABEL)
3860             {
3861               djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
3862
3863               /* If we're fully characterized the use the equivalence.  */
3864               if (djt->touch_count == djt->reach_count)
3865                 {
3866                   dp_current = djt->dp_equiv;
3867                   dp_current_ok = 1;
3868                   continue;
3869                 }
3870
3871               /* If we have a known equivalence for DP as we reach the
3872                  fallthrough-edge then track this into the code label.  */
3873               if (dp_current_ok
3874                   && (! prev_nonnote_insn (insn)
3875                       || (prev_nonnote_insn (insn)
3876                           && GET_CODE (prev_nonnote_insn (insn)) != BARRIER)))
3877                 {
3878                   if (djt->touch_count == 0)
3879                     djt->dp_equiv = dp_current;
3880
3881                   if (djt->touch_count < djt->reach_count)
3882                     {
3883                       djt->touch_count++;
3884                       if (! rtx_equal_p (djt->dp_equiv, dp_current))
3885                         {
3886                           /* When we definitely know that we can't form an
3887                              equivalence for DP here we must clobber anything
3888                              that we'd started to track too.  */
3889                           djt->dp_equiv = NULL_RTX;
3890                           dp_current = NULL_RTX;
3891                           dp_current_ok = 1;
3892                         }
3893                     }
3894                 }
3895
3896               /* If we've not completely characterized this code label then
3897                  be cautious and assume that we don't know what DP is
3898                  equivalent to.  */
3899               if (djt->touch_count < djt->reach_count)
3900                 {
3901                   dp_current = NULL_RTX;
3902                   dp_current_ok = 0;
3903                 }
3904
3905               continue;
3906             }
3907
3908           /* If we've hit a jump insn then we look for either an address
3909              vector (jump table) or for jump label references.  */
3910           if (GET_CODE (insn) == JUMP_INSN)
3911             {
3912               /* Don't attempt to track here if we don't have a known
3913                  equivalence for DP at this point.  */
3914               if (dp_current_ok)
3915                 {
3916                   rtx pat = PATTERN (insn);
3917                   if (GET_CODE (pat) == ADDR_VEC)
3918                     {
3919                       int i;
3920                       int len = XVECLEN (pat, 0);
3921
3922                       for (i = 0; i < len; i++)
3923                         {
3924                           rtx vec_insn = XEXP (XVECEXP (pat, 0, i), 0);
3925                           djt = &ip2k_dpre_jump_targets [INSN_UID (vec_insn)];
3926
3927                           if (djt->touch_count == 0)
3928                             djt->dp_equiv = dp_current;
3929
3930                           if (djt->touch_count < djt->reach_count)
3931                             {
3932                               djt->touch_count++;
3933                               if (! rtx_equal_p (djt->dp_equiv, dp_current))
3934                                 djt->dp_equiv = NULL_RTX;
3935                             }
3936                         }
3937                     }
3938                   else if (JUMP_LABEL (insn))
3939                     {
3940                       rtx j_insn = JUMP_LABEL (insn);
3941                       djt = &ip2k_dpre_jump_targets[INSN_UID (j_insn)];
3942
3943                       if (djt->touch_count == 0)
3944                         djt->dp_equiv = dp_current;
3945
3946                       if (djt->touch_count < djt->reach_count)
3947                         {
3948                           djt->touch_count++;
3949                           if (! rtx_equal_p (djt->dp_equiv, dp_current))
3950                             djt->dp_equiv = NULL_RTX;
3951                         }
3952                     }
3953                 }
3954
3955               continue;
3956             }
3957
3958           /* Anything other than a code labal or jump arrives here.
3959              We try and track DP, but sometimes we might not be able to.  */
3960           dp_current_ok = track_dp_reload (insn, &dp_current,
3961                                            dp_current_ok, 0);
3962         }
3963
3964       /* When we're looking to see if we've finished we count the number of
3965          paths through the code labels where we weren't able to definitively
3966          track DP.
3967          This number is used to see if we're converging on a solution.
3968          If this hits zero then we've fully converged, but if this stays the
3969          same as last time then we probably can't make any further
3970          progress.  */
3971       incomplete_scan = 0;
3972       for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3973         {
3974           if (GET_CODE (insn) == CODE_LABEL)
3975             {
3976               djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
3977               if (djt->touch_count != djt->reach_count)
3978                 {
3979                   incomplete_scan += (djt->reach_count - djt->touch_count);
3980                   djt->dp_equiv = NULL_RTX;
3981                   djt->touch_count = 0;
3982                 }
3983             }
3984         }
3985     }
3986   while (incomplete_scan && incomplete_scan != last_incomplete_scan);
3987
3988   /* Finally we scan the whole function and run DP elimination.  When we hit
3989      a CODE_LABEL we pick up any stored equivalence since we now know that
3990      every path to this point entered with DP holding the same thing!  If
3991      we subsequently have a reload that matches then we can eliminate it.  */
3992   dp_current = NULL_RTX;
3993   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3994     {
3995       if (GET_CODE (insn) == JUMP_INSN)
3996         continue;
3997
3998       if (GET_CODE (insn) == CODE_LABEL)
3999         {
4000           djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
4001           dp_current = djt->dp_equiv;
4002           continue;
4003         }
4004
4005       track_dp_reload (insn, &dp_current, 1, 1);
4006     }
4007
4008   free (ip2k_dpre_jump_targets);
4009 }
4010
4011 /* As part of the machine-dependent reorg we look for reloads of DP
4012    that we can move to earlier points within the file.
4013    Moving these out of the way allows more peepholes to match.  */
4014
4015 static void
4016 mdr_try_move_dp_reload (first_insn)
4017      rtx first_insn;
4018 {
4019   rtx insn;
4020   rtx set;
4021   rtx orig_first;
4022
4023   /* Don't try to match the first instruction because we can't move it
4024      anyway.  */
4025   orig_first = first_insn;
4026   first_insn = next_nonnote_insn (first_insn);
4027   
4028   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4029     {
4030       if (GET_CODE (insn) != INSN)
4031         continue;
4032
4033       set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4034       if (set == NULL_RTX)
4035         continue;
4036
4037       /* Look for DP being loaded.  When we find this we start a rewind
4038          scan looking for possible positions to move this to.  */
4039       if (GET_CODE (XEXP (set, 0)) == REG
4040           && REGNO (XEXP (set, 0)) == REG_DP
4041           && GET_MODE (XEXP (set, 0)) == HImode)
4042         {
4043           int try_again;
4044           rtx try_insn = insn;
4045
4046           do
4047             {
4048               rtx rewind;
4049               rtx check;
4050
4051               try_again = 0;
4052               
4053               /* For now we do the *really* simple version of things and only
4054                  attempt to move the load of DP if it's very safe to do so.  */
4055               rewind = prev_nonnote_insn (try_insn);
4056               if (rewind != orig_first && rewind != NULL_RTX
4057                   && GET_CODE (rewind) == INSN)
4058                 {
4059                   check = ((GET_CODE (PATTERN (rewind)) == SET)
4060                            ? PATTERN (rewind) : NULL_RTX);
4061                   if (check != NULL_RTX
4062                       && ip2k_composite_xexp_not_uses_cc0_p (XEXP (check, 0))
4063                       && ip2k_composite_xexp_not_uses_cc0_p (XEXP (check, 1)))
4064                     {
4065                       if (GET_CODE (XEXP (check, 0)) == REG
4066                           && REGNO (XEXP (check, 0)) != REG_DPH
4067                           && REGNO (XEXP (check, 0)) != REG_DPL
4068                           && (ip2k_composite_xexp_not_uses_reg_p
4069                               (XEXP (check, 1), REG_DP, 2))
4070                           && (ip2k_composite_xexp_not_uses_reg_p
4071                               (XEXP (set, 1),
4072                                REGNO (XEXP (check, 0)),
4073                                GET_MODE_SIZE (GET_MODE (XEXP (check, 0))))))
4074                         {
4075                           emit_insn_before (set, rewind);
4076                           if (try_insn == insn)
4077                             insn = prev_nonnote_insn (insn);
4078                           delete_insn (try_insn);
4079                           try_insn = prev_nonnote_insn (rewind);
4080                           try_again = 1;
4081                         }
4082                       else if (GET_CODE (XEXP (set, 1)) == REG
4083                                && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 1), REG_DP, 2)
4084                                && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 0), REG_DP, 2)
4085                                && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 0), REGNO (XEXP (set, 1)),
4086                                                                       GET_MODE_SIZE (GET_MODE (XEXP (set, 1)))))
4087                         {
4088                           emit_insn_before (set, rewind);
4089                           if (try_insn == insn)
4090                             insn = prev_nonnote_insn (insn);
4091                           delete_insn (try_insn);
4092                           try_insn = prev_nonnote_insn (rewind);
4093                           try_again = 1;
4094                         }
4095                     }
4096                 }
4097             }
4098           while (try_again && try_insn);
4099         }
4100     }
4101 }
4102 #endif /* IP2K_MD_REORG_PASS */
4103
4104 /* Look to see if the expression, x, can have any stack references offset by
4105    a fixed constant, offset.  If it definitely can then returns nonzero.  */
4106
4107 static int
4108 ip2k_check_can_adjust_stack_ref (rtx x, int offset)
4109 {
4110   if (ARITHMETIC_P (x))
4111     return (ip2k_check_can_adjust_stack_ref (XEXP (x, 0), offset)
4112             && ip2k_check_can_adjust_stack_ref (XEXP (x, 1), offset));
4113
4114   if (UNARY_P (x))
4115     return ip2k_check_can_adjust_stack_ref (XEXP (x, 0), offset);
4116
4117   switch (GET_CODE (x))
4118     {
4119     case REG:
4120       return (REGNO (x) != REG_SPH && REGNO (x) != REG_SPL);
4121
4122     case MEM:
4123       if (GET_CODE (XEXP (x, 0)) != PLUS)
4124         return 1;
4125
4126       if (GET_CODE (XEXP (XEXP (x, 0), 0)) != REG)
4127         return 1;
4128
4129       if (REGNO (XEXP (XEXP (x, 0), 0)) != REG_SP)
4130         return 1;
4131
4132       /* We can't allow this if the adjustment will create an
4133          invalid address.  */
4134       return (INTVAL (XEXP (XEXP (x, 0), 1))
4135               + offset <= (128 - 2 * GET_MODE_SIZE (GET_MODE (x))));
4136
4137     case CONST:
4138     case CONST_INT:
4139     case CONST_DOUBLE:
4140     case SYMBOL_REF:
4141     case LABEL_REF:
4142       return 1;
4143
4144     default:
4145       return 0;
4146     }
4147 }
4148
4149 /* Adjusts all of the stack references in the expression pointed to by x by
4150    a fixed offset.  */
4151
4152 static void
4153 ip2k_adjust_stack_ref (rtx *x, int offset)
4154 {
4155   if (ARITHMETIC_P (*x))
4156     {
4157       ip2k_adjust_stack_ref (&XEXP (*x, 0), offset);
4158       ip2k_adjust_stack_ref (&XEXP (*x, 1), offset);
4159       return;
4160     }
4161
4162   if (UNARY_P (*x))
4163     {
4164       ip2k_adjust_stack_ref (&XEXP (*x, 0), offset);
4165       return;
4166     }
4167
4168   switch (GET_CODE (*x))
4169     {
4170     case MEM:
4171       if (GET_CODE (XEXP (*x, 0)) != PLUS)
4172         return;
4173
4174       if (GET_CODE (XEXP (XEXP (*x, 0), 0)) != REG)
4175         return;
4176
4177       if (REGNO (XEXP (XEXP (*x, 0), 0)) != REG_SP)
4178         return;
4179
4180       *x = copy_rtx (*x);
4181       XEXP (XEXP (*x, 0), 1) = GEN_INT (INTVAL (XEXP (XEXP (*x, 0), 1))
4182                                         + offset);
4183       break;
4184
4185     default:
4186       break;
4187     }
4188 }
4189
4190 #ifdef IP2K_MD_REORG_PASS
4191 /* As part of the machine-dependent reorg we look to move push instructions
4192    to earlier points within the file.  Moving these out of the way allows more
4193    peepholes to match.  */
4194
4195 static void
4196 mdr_try_move_pushes (first_insn)
4197      rtx first_insn;
4198 {
4199   rtx insn;
4200   rtx set;
4201   rtx orig_first;
4202
4203   /* Don't try to match the first instruction because we can't move
4204      it anyway.  */
4205   orig_first = first_insn;
4206   first_insn = next_nonnote_insn (first_insn);
4207   
4208   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4209     {
4210       if (GET_CODE (insn) != INSN)
4211         continue;
4212
4213       set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4214       if (set == NULL_RTX)
4215         continue;
4216
4217       /* Have we found a push instruction?  */
4218       if (GET_CODE (XEXP (set, 0)) == MEM
4219           && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
4220           && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
4221           && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
4222           && GET_CODE (XEXP (set, 1)) == REG)
4223         {
4224           rtx try_insn = insn;
4225           unsigned int regno = REGNO (XEXP (set, 1));
4226           int reg_range = GET_MODE_SIZE (GET_MODE (XEXP (set, 1)));
4227
4228           while (1)
4229             {
4230               rtx rewind;
4231               rtx check;
4232
4233               rewind = prev_nonnote_insn (try_insn);
4234               if (rewind == orig_first || rewind == NULL_RTX
4235                   || GET_CODE (rewind) != INSN)
4236                 break;
4237
4238               check = (GET_CODE (PATTERN (rewind)) == SET) ? PATTERN (rewind) : NULL_RTX;
4239               if (check == NULL_RTX)
4240                 break;
4241
4242               if (! ip2k_check_can_adjust_stack_ref (XEXP (check, 0),
4243                                                      reg_range)
4244                   || ! ip2k_check_can_adjust_stack_ref (XEXP (check, 1),
4245                                                         reg_range))
4246                 break;
4247
4248               /* If we've hit another push instruction we can't go any
4249                  further.  */
4250               if (GET_CODE (XEXP (check, 0)) == MEM
4251                   && GET_CODE (XEXP (XEXP (check, 0), 0)) == POST_DEC
4252                   && GET_CODE (XEXP (XEXP (XEXP (check, 0), 0), 0)) == REG
4253                   && REGNO (XEXP (XEXP (XEXP (check, 0), 0), 0)) == REG_SP)
4254                 break;
4255
4256               /* If this is a register move then check that it doesn't clobber
4257                  SP or any part of the instruction we're trying to move.  */
4258               if (GET_CODE (XEXP (check, 0)) == REG)
4259                 {
4260                   unsigned int check_reg = REGNO (XEXP (check, 0));
4261                   int check_reg_range = GET_MODE_SIZE (GET_MODE (XEXP (check,
4262                                                                        0)));
4263
4264                   /* If we have a special case where what we want to push is
4265                      being loaded by this "clobbering" insn then we can just
4266                      push what is being used to load us and then do the load.
4267                      This may seem a little odd, but we may subsequently be
4268                      able to merge the load with another instruction as it
4269                      may only be used once now!  Note though that we
4270                      specifically don't try this if the expression being
4271                      loaded is an HImode MEM using IP.  */
4272                   if (check_reg == regno
4273                       && check_reg_range == reg_range
4274                       && ((GET_CODE (XEXP (check, 1)) == REG
4275                           || (GET_CODE (XEXP (check, 1)) == MEM
4276                               && (GET_MODE (XEXP (check, 1)) != HImode
4277                                   || ip2k_xexp_not_uses_reg_for_mem (XEXP (check, 1), REG_IP))))))
4278                     {
4279                       switch (check_reg_range)
4280                         {
4281                         case 1:
4282                           emit_insn_before (gen_movqi (XEXP (set, 0),
4283                                                        XEXP (check, 1)),
4284                                             rewind);
4285                           delete_insn (try_insn);
4286                           break;
4287
4288                         case 2:
4289                           emit_insn_before (gen_movhi (XEXP (set, 0),
4290                                                        XEXP (check, 1)),
4291                                             rewind);
4292                           delete_insn (try_insn);
4293                           break;
4294
4295                         case 4:
4296                           emit_insn_before (gen_movsi (XEXP (set, 0),
4297                                                        XEXP (check, 1)),
4298                                             rewind);
4299                           delete_insn (try_insn);
4300                           break;
4301
4302                         case 8:
4303                           emit_insn_before (gen_movdi (XEXP (set, 0),
4304                                                        XEXP (check, 1)),
4305                                             rewind);
4306                           delete_insn (try_insn);
4307                           break;
4308                         }
4309
4310                       ip2k_adjust_stack_ref (&XEXP (check, 0), reg_range);
4311                       ip2k_adjust_stack_ref (&XEXP (check, 1), reg_range);
4312                       try_insn = prev_nonnote_insn (rewind);
4313                       /* XXX - should be a continue?  */
4314                       break;
4315                     }
4316                   
4317                   if ((check_reg == REG_SPL)
4318                       || (check_reg == REG_SPH)
4319                       || (((regno <= check_reg)
4320                            && (regno + reg_range - 1) >= check_reg)
4321                       || ((regno <= (check_reg + check_reg_range - 1))
4322                           && ((regno + reg_range - 1)
4323                               >= (check_reg + check_reg_range - 1)))))
4324                     break;
4325                 }
4326
4327               emit_insn_before (set, rewind);
4328               delete_insn (try_insn);
4329               ip2k_adjust_stack_ref (&XEXP (check, 0), reg_range);
4330               ip2k_adjust_stack_ref (&XEXP (check, 1), reg_range);
4331               try_insn = prev_nonnote_insn (rewind);
4332             }
4333         }
4334     }
4335 }
4336
4337 /* Assist the following function, mdr_try_propagate_clr().  */
4338
4339 static void
4340 mdr_try_propagate_clr_sequence (first_insn, regno)
4341      rtx first_insn;
4342      unsigned int regno;
4343 {
4344   rtx try_insn;
4345
4346   for (try_insn = next_nonnote_insn (first_insn); try_insn;
4347        try_insn = next_nonnote_insn (try_insn))
4348     {
4349       rtx new_insn = NULL_RTX;
4350       rtx set2;
4351
4352       if (GET_CODE (try_insn) == JUMP_INSN)
4353         continue;
4354
4355       if (GET_CODE (try_insn) != INSN)
4356         break;
4357
4358       set2 = ((GET_CODE (PATTERN (try_insn)) == SET)
4359               ? PATTERN (try_insn) : NULL_RTX);
4360       if (set2 == NULL_RTX)
4361         continue;
4362
4363       if (GET_CODE (XEXP (set2, 1)) == AND
4364           && ((GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4365                && REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
4366               || (GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4367                   && REGNO (XEXP (XEXP (set2, 1), 1)) == regno)))
4368         {
4369           rtx remove_insn = try_insn;
4370           try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4371                                                     const0_rtx), try_insn);
4372           delete_insn (remove_insn);
4373         }
4374       else if (GET_CODE (XEXP (set2, 1)) == IOR
4375                && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4376                && REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
4377         {
4378           rtx remove_insn = try_insn;
4379           try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4380                                                     XEXP (XEXP (set2, 1), 1)),
4381                                        try_insn);
4382           delete_insn (remove_insn);
4383         }
4384       else if (GET_CODE (XEXP (set2, 1)) == IOR
4385                && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4386                && REGNO (XEXP (XEXP (set2, 1), 1)) == regno)
4387         {
4388           rtx remove_insn = try_insn;
4389           try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4390                                                     XEXP (XEXP (set2, 1), 0)),
4391                                        try_insn);
4392           delete_insn (remove_insn);
4393         }
4394       else if (GET_CODE (XEXP (set2, 1)) == XOR
4395                && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4396                && REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
4397         {
4398           rtx remove_insn = try_insn;
4399           try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4400                                                     XEXP (XEXP (set2, 1), 1)),
4401                                        try_insn);
4402           delete_insn (remove_insn);
4403         }
4404       else if (GET_CODE (XEXP (set2, 1)) == XOR
4405                && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4406                && REGNO (XEXP (XEXP (set2, 1), 1)) == regno)
4407         {
4408           rtx remove_insn = try_insn;
4409           try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4410                                                     XEXP (XEXP (set2, 1), 0)),
4411                                        try_insn);
4412           delete_insn (remove_insn);
4413         }
4414       
4415       if (GET_CODE (XEXP (set2, 0)) == REG)
4416         {
4417           int reg2_range = GET_MODE_SIZE (GET_MODE (XEXP (set2, 0)));
4418           unsigned int regno2 = REGNO (XEXP (set2, 0));
4419
4420           if (reg2_range == 1
4421               && regno == regno2
4422               && GET_CODE (XEXP (set2, 1)) == CONST_INT)
4423             {
4424               int iv = INTVAL (XEXP (set2, 1));
4425               if (iv == 0xff)
4426                 iv = -1;
4427               if (iv == 1 || iv == -1)
4428                 {
4429                   new_insn = gen_rtx_SET (QImode, XEXP (set2, 0),
4430                                           gen_rtx_PLUS (QImode, XEXP (set2, 0),
4431                                                         GEN_INT (iv)));
4432                   new_insn = emit_insn_before (new_insn, try_insn);
4433                   delete_insn (try_insn);
4434                   try_insn = new_insn;
4435                 }
4436               break;
4437             }
4438
4439           if ((regno >= regno2) && (regno <= regno2 + reg2_range - 1))
4440             break;
4441
4442           if (GET_CODE (XEXP (set2, 1)) == REG
4443               && REGNO (XEXP (set2, 1)) == regno)
4444             {
4445               new_insn = emit_insn_before (gen_rtx_SET (QImode,
4446                                                         XEXP (set2, 0),
4447                                                         const0_rtx),
4448                                            try_insn);
4449               delete_insn (try_insn);
4450               try_insn = new_insn;
4451             }
4452         }
4453
4454       if (GET_CODE (XEXP (set2, 0)) == CC0)
4455         {
4456           if (GET_CODE (XEXP (set2, 1)) == REG
4457               && GET_MODE_SIZE (GET_MODE (XEXP (set2, 1))) == 2
4458               && REGNO (XEXP (set2, 1)) == regno)
4459             {
4460               new_insn = gen_rtx_SET (VOIDmode, gen_rtx_CC0 (VOIDmode),
4461                                       gen_rtx_REG(QImode, regno + 1));
4462               new_insn = emit_insn_before (new_insn, try_insn);
4463             }
4464           else if (GET_CODE (XEXP (set2, 1)) == COMPARE
4465                    && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4466                    && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 0))) == 2
4467                    && REGNO (XEXP (XEXP (set2, 1), 0)) == regno
4468                    && GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST_INT
4469                    && INTVAL (XEXP (XEXP (set2, 1), 1)) >= 0
4470                    && INTVAL (XEXP (XEXP (set2, 1), 1)) < 256)
4471             {
4472               new_insn = gen_rtx_SET (VOIDmode, cc0_rtx,
4473                                       gen_rtx_COMPARE(QImode,
4474                                                       gen_rtx_REG (QImode,
4475                                                                   regno + 1),
4476                                                       XEXP (XEXP (set2, 1),
4477                                                             1)));
4478               new_insn = emit_insn_before (new_insn, try_insn);
4479             }
4480
4481           /* If we have inserted a replacement for a CC0 setter operation
4482              then we need to delete the old one.  */
4483           if (new_insn != NULL_RTX)
4484             {
4485               delete_insn (try_insn);
4486               try_insn = new_insn;
4487
4488               /* Now as we know that we have just done an unsigned compare
4489                  (remember we were zero-extended by the clr!) we also know
4490                  that we don't need a signed jump insn.  If we find that
4491                  our next isns is a signed jump then make it unsigned!  */
4492               if (GET_CODE (next_nonnote_insn (try_insn)) == JUMP_INSN)
4493                 {
4494                   rtx set3;
4495
4496                   try_insn = next_nonnote_insn (try_insn);
4497                   set3 = ((GET_CODE (PATTERN (try_insn)) == SET)
4498                           ? PATTERN (try_insn) : NULL_RTX);
4499                   if (set3 == NULL_RTX)
4500                     continue;
4501
4502                   /* If we discover that our jump target is only accessible
4503                      from here then we can continue our "clr" propagation to
4504                      it too!  */
4505                   if (LABEL_NUSES (JUMP_LABEL (try_insn)) == 1)
4506                     mdr_try_propagate_clr_sequence (JUMP_LABEL (try_insn),
4507                                                     regno);
4508
4509                   if (GET_CODE (XEXP (set3, 0)) == PC
4510                       && GET_CODE (XEXP (set3, 1)) == IF_THEN_ELSE
4511                       && (GET_CODE (XEXP (XEXP (set3, 1), 0)) == GT
4512                           || GET_CODE (XEXP (XEXP (set3, 1), 0)) == GE
4513                           || GET_CODE (XEXP (XEXP (set3, 1), 0)) == LT
4514                           || GET_CODE (XEXP (XEXP (set3, 1), 0)) == LE)
4515                       && GET_CODE (XEXP (XEXP (XEXP (set3, 1), 0), 0)) == CC0
4516                       && (GET_CODE (XEXP (XEXP (XEXP (set3, 1), 0), 1))
4517                           == CONST_INT)
4518                       && GET_CODE (XEXP (XEXP (set3, 1), 1)) == LABEL_REF
4519                       && GET_CODE (XEXP (XEXP (set3, 1), 2)) == PC)
4520                     {
4521                       enum rtx_code code;
4522                       rtx new_if;
4523                       rtx cmp;
4524
4525                       /* Replace our old conditional jump with a new one that
4526                          does the unsigned form of what was previously a
4527                          signed comparison.  */
4528                       code = GET_CODE (XEXP (XEXP (set3, 1), 0));
4529                       cmp = gen_rtx_fmt_ee ((code == GT
4530                                              ? GTU
4531                                              : (code == GE
4532                                                 ? GEU
4533                                                 : (code == LT ? LTU : LEU))),
4534                                             VOIDmode,
4535                                             XEXP (XEXP (XEXP (set3, 1), 0), 0),
4536                                             XEXP (XEXP (XEXP (set3, 1), 0),
4537                                                   1));
4538                       new_if
4539                         = gen_rtx_SET (GET_MODE (set3),
4540                                        pc_rtx,
4541                                        gen_rtx_IF_THEN_ELSE
4542                                        (GET_MODE (XEXP (set3, 1)), cmp,
4543                                         XEXP (XEXP (set3, 1), 1),
4544                                         XEXP (XEXP (set3, 1), 2)));
4545                       new_insn = emit_jump_insn_before (new_if, try_insn);
4546                       LABEL_NUSES (JUMP_LABEL (try_insn))++;
4547                       delete_insn (try_insn);
4548                       try_insn = new_insn;
4549                     }
4550                 }
4551             }
4552         }
4553       else if (GET_CODE (XEXP (set2, 1)) == PLUS
4554                && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4555                && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 0))) == 2
4556                && REGNO (XEXP (XEXP (set2, 1), 0)) == regno
4557                && (GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4558                    || GET_CODE (XEXP (XEXP (set2, 1), 1)) == MEM
4559                    || GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST_INT
4560                    || GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST
4561                    || GET_CODE (XEXP (XEXP (set2, 1), 1)) == SYMBOL_REF))
4562         {
4563           rtx extend = gen_rtx_ZERO_EXTEND (HImode,
4564                                             gen_rtx_REG (QImode, regno + 1));
4565           new_insn = gen_rtx_SET (HImode, XEXP (set2, 0),
4566                                   gen_rtx_PLUS (HImode, extend,
4567                                                 XEXP (XEXP (set2, 1), 1)));
4568           new_insn = emit_insn_before (new_insn, try_insn);
4569           delete_insn (try_insn);
4570           try_insn = new_insn;
4571         }
4572       else if (GET_CODE (XEXP (set2, 1)) == PLUS
4573                && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4574                && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 1))) == 2
4575                && REGNO (XEXP (XEXP (set2, 1), 1)) == regno
4576                && (GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4577                    || GET_CODE (XEXP (XEXP (set2, 1), 0)) == MEM
4578                    || GET_CODE (XEXP (XEXP (set2, 1), 0)) == CONST_INT
4579                    || GET_CODE (XEXP (XEXP (set2, 1), 0)) == CONST
4580                    || GET_CODE (XEXP (XEXP (set2, 1), 0)) == SYMBOL_REF))
4581         {
4582           rtx t_src = gen_rtx_PLUS (HImode,
4583                                     gen_rtx_ZERO_EXTEND (HImode,
4584                                                          gen_rtx_REG (QImode,
4585                                                                       regno
4586                                                                       + 1)),
4587                                     XEXP (XEXP (set2, 1), 0));
4588           new_insn = emit_insn_before (gen_rtx_SET (HImode, XEXP (set2, 0),
4589                                                     t_src),
4590                                        try_insn);
4591           delete_insn (try_insn);
4592           try_insn = new_insn;
4593         }
4594     }
4595 }
4596
4597 /* One of the things that can quite often happen with an 8-bit CPU is that
4598    we end up clearing the MSByte of a 16-bit value.  Unfortunately, all too
4599    often gcc doesn't have any way to realize that only half of the value is
4600    useful and ends up doing more work than it should.  We scan for such
4601    occurrences here, track them and reduce compare operations to a smaller
4602    size where possible.
4603  
4604    Note that this is somewhat different to move propagation as we may
4605    actually change some instruction patterns when we're doing this whereas
4606    move propagation is just about doing a search and replace.  */
4607
4608 static void
4609 mdr_try_propagate_clr (first_insn)
4610      rtx first_insn;
4611 {
4612   rtx insn;
4613   rtx set;
4614
4615   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4616     {
4617       if (GET_CODE (insn) != INSN)
4618         continue;
4619
4620       set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4621       if (set == NULL_RTX)
4622         continue;
4623
4624       /* Have we found a "clr" instruction?  */
4625       if (GET_CODE (XEXP (set, 0)) == REG
4626           && GET_CODE (XEXP (set, 1)) == CONST_INT
4627           && GET_MODE_SIZE (GET_MODE (XEXP (set, 0))) == 1
4628           && INTVAL (XEXP (set, 1)) == 0)
4629         {
4630           mdr_try_propagate_clr_sequence (insn, REGNO (XEXP (set, 0)));
4631         }
4632     }
4633 }
4634 #endif /* IP2K_MD_REORG_PASS */
4635
4636 /* Look to see if the expression, x, does not make any memory references
4637    via the specified register.  This is very conservative and only returns
4638    nonzero if we definitely don't have such a memory ref.  */
4639
4640 static int
4641 ip2k_xexp_not_uses_reg_for_mem (rtx x, unsigned int regno)
4642 {
4643   if (regno & 1)
4644     regno &= 0xfffffffe;
4645
4646   switch (GET_CODE (x))
4647     {
4648     case REG:
4649       return 1;
4650
4651     case MEM:
4652       if ((GET_CODE (XEXP (x, 0)) == PLUS
4653            && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
4654            && REGNO (XEXP (XEXP (x, 0), 0)) == regno)
4655           || (GET_CODE (XEXP (x, 0)) == REG
4656               && REGNO (XEXP (x, 0)) == regno))
4657         return 0;
4658       else
4659         return 1;
4660
4661     case CONST:
4662     case CONST_INT:
4663     case CONST_DOUBLE:
4664     case SYMBOL_REF:
4665     case LABEL_REF:
4666     case CC0:
4667     case PC:
4668       return 1;
4669
4670     default:
4671       if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS)
4672         return (ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno)
4673                 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 1), regno)
4674                 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 2), regno));
4675
4676       if (BINARY_P (x))
4677         return (ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno)
4678                 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 1), regno));
4679
4680       if (UNARY_P (x)
4681           || GET_RTX_CLASS (GET_CODE (x)) == '3')
4682         return ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno);
4683
4684       return 0;
4685     }
4686 }
4687
4688 #ifdef IP2K_MD_REORG_PASS
4689 /* Assist the following function, mdr_try_propagate_move().  */
4690
4691 static void
4692 mdr_try_propagate_move_sequence (first_insn, orig, equiv)
4693      rtx first_insn;
4694      rtx orig;
4695      rtx equiv;
4696 {
4697   rtx try_insn;
4698
4699   for (try_insn = next_nonnote_insn (first_insn); try_insn;
4700        try_insn = next_nonnote_insn (try_insn))
4701     {
4702       rtx set;
4703       int range;
4704       rtx new_equiv = NULL_RTX;
4705
4706       if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
4707         break;
4708
4709       set = single_set (try_insn);
4710       if (set == NULL_RTX)
4711         break;
4712
4713       range = MAX (GET_MODE_SIZE (GET_MODE (equiv)),
4714                    GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
4715
4716       if (GET_CODE (equiv) == REG
4717           && REGNO (equiv) == REG_W
4718           && (recog_memoized (try_insn) < 0
4719               || get_attr_clobberw (try_insn) != CLOBBERW_NO)
4720           && (! (GET_CODE (XEXP (set, 0)) == REG
4721                  && REGNO (XEXP (set, 0)) == REG_W
4722                  && rtx_equal_p (XEXP (set, 1), orig))))
4723         break;
4724       else if (GET_CODE (XEXP (set, 0)) == REG
4725           && (REGNO (XEXP (set, 0)) == REG_SP
4726               || ! ip2k_xexp_not_uses_reg_p (equiv, REGNO (XEXP (set, 0)),
4727                                              range)
4728               || ! ip2k_xexp_not_uses_reg_p (orig, REGNO (XEXP (set, 0)),
4729                                              range))
4730           && ! rtx_equal_p (equiv, XEXP (set, 0))
4731           && ! rtx_equal_p (orig, XEXP (set, 0)))
4732         break;
4733       else if (GET_CODE (orig) == REG
4734                && (REGNO (orig) == REG_IPL
4735                    || REGNO (orig) == REG_IPH
4736                    || REGNO (orig) == REG_DPL
4737                    || REGNO (orig) == REG_DPH)
4738                && (! ip2k_xexp_not_uses_reg_for_mem (XEXP (set, 0),
4739                                                      REGNO (orig))
4740                    || ! ip2k_xexp_not_uses_reg_for_mem (XEXP (set, 1),
4741                                                         REGNO (orig))))
4742         break;
4743       else if (GET_CODE (XEXP (set, 0)) == MEM
4744                && GET_CODE (equiv) == MEM)
4745         {
4746           if (! ip2k_xexp_not_uses_reg_p (equiv, REG_SP, 2))
4747             {
4748               if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2))
4749                 {
4750                   /* We look for a special case of "push" operations screwing
4751                      our register equivalence when it's based on a stack slot.
4752                      We can track this one and replace the old equivalence
4753                      expression with a new one.  */
4754                   if (GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
4755                       && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
4756                       && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
4757                       && GET_CODE (XEXP (equiv, 0)) == PLUS
4758                       && REGNO (XEXP (XEXP (equiv, 0), 0)) == REG_SP)
4759                     {
4760                       int md_size = GET_MODE_SIZE (GET_MODE (XEXP (set, 0)));
4761                       int new_sp_offs = INTVAL (XEXP (XEXP (equiv, 0), 1))
4762                         + md_size;
4763
4764                       /* Don't allow an invalid stack pointer offset to be
4765                          created.  */
4766                       if (new_sp_offs > (128 - 2 * md_size))
4767                         break;
4768
4769                       new_equiv
4770                         = gen_rtx_MEM (GET_MODE (equiv),
4771                                        gen_rtx_PLUS (Pmode,
4772                                                      gen_rtx_REG (HImode ,
4773                                                                   REG_SP),
4774                                                      GEN_INT (new_sp_offs)));
4775                     }
4776                   else if (! rtx_equal_p (equiv, XEXP (set, 0)))
4777                     {
4778                       /* Look at the SP offsets and look for any overlaps.  */
4779                       int equiv_offs = GET_CODE (XEXP (equiv, 0)) == PLUS
4780                                        ? INTVAL (XEXP (XEXP (equiv, 0), 1))
4781                                        : 0;
4782                       int set_offs
4783                         = (GET_CODE (XEXP (XEXP (set, 0), 0)) == PLUS
4784                            ? INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1))
4785                            : 0);
4786
4787                       if (abs (equiv_offs - set_offs) < range)
4788                         break;
4789                     }
4790                 }
4791             }
4792
4793           if (! ip2k_xexp_not_uses_reg_p (equiv, REG_IP, 2))
4794             break;
4795
4796           if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_DP, 2)
4797               && ! ip2k_xexp_not_uses_reg_p (equiv, REG_DP, 2)
4798               && ! rtx_equal_p (equiv, XEXP (set, 0)))
4799             {
4800               /* Look at the DP offsets and look for any overlaps.  */
4801               int equiv_offs = GET_CODE (XEXP (equiv, 0)) == PLUS
4802                                ? INTVAL (XEXP (XEXP (equiv, 0), 1))
4803                                : 0;
4804               int set_offs = GET_CODE (XEXP (XEXP (set, 0), 0)) == PLUS
4805                              ? INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1))
4806                              : 0;
4807
4808               if (abs (equiv_offs - set_offs) < range)
4809                 break;
4810             }
4811         }
4812
4813       validate_replace_rtx_subexp (orig, equiv, try_insn, &XEXP (set, 1));
4814
4815       if (rtx_equal_p (equiv, XEXP (set, 0))
4816           || rtx_equal_p (orig, XEXP (set, 0)))
4817         break;
4818
4819       if (new_equiv != NULL_RTX)
4820         equiv = new_equiv;
4821     }
4822 }
4823
4824 /* Try propagating move instructions forwards.  It may be that we can
4825    replace a register use with an equivalent expression that already
4826    holds the same value and thus allow one or more register loads to
4827    be eliminated.  */
4828
4829 static void
4830 mdr_try_propagate_move (first_insn)
4831      rtx first_insn;
4832 {
4833   rtx insn;
4834   rtx set;
4835
4836   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4837     {
4838       if (GET_CODE (insn) != INSN)
4839         continue;
4840
4841       set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4842       if (set == NULL_RTX)
4843         continue;
4844
4845       /* Have we found a simple move instruction?  */
4846       if (GET_CODE (XEXP (set, 0)) == REG
4847           && (REGNO (XEXP (set, 0)) >= 0x80
4848               || REGNO (XEXP (set, 0)) == REG_DPL
4849               || REGNO (XEXP (set, 0)) == REG_DPH
4850               || REGNO (XEXP (set, 0)) == REG_IPL
4851               || REGNO (XEXP (set, 0)) == REG_IPH)
4852           && ((GET_CODE (XEXP (set, 1)) == REG
4853                && REGNO (XEXP (set, 1)) != REG_SP
4854                && ip2k_xexp_not_uses_reg_p (XEXP (set, 0),
4855                                             REGNO (XEXP (set, 1)),
4856                                             GET_MODE_SIZE (GET_MODE (XEXP (set,
4857                                                                            0)))))
4858               || (GET_CODE (XEXP (set, 1)) == MEM
4859                   && (ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_IP, 2)
4860                       || GET_MODE (XEXP (set, 1)) == QImode)
4861                   && ((REGNO (XEXP (set, 0)) != REG_DPH
4862                        && REGNO (XEXP (set, 0)) != REG_DPL)
4863                       || ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_DP, 2)))
4864               || (GET_CODE (XEXP (set, 1)) == CONST_INT
4865                   && (GET_MODE (XEXP (set, 0)) != QImode
4866                       || INTVAL (XEXP (set, 1)) != 0))
4867               || GET_CODE (XEXP (set, 1)) == CONST_DOUBLE
4868               || GET_CODE (XEXP (set, 1)) == CONST
4869               || GET_CODE (XEXP (set, 1)) == SYMBOL_REF))
4870         {
4871           mdr_try_propagate_move_sequence (insn, XEXP (set, 0), XEXP (set, 1));
4872         }
4873     }
4874 }
4875
4876 /* Try to remove redundant instructions.  */
4877
4878 static void
4879 mdr_try_remove_redundant_insns (first_insn)
4880      rtx first_insn;
4881 {
4882   rtx insn;
4883
4884   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4885     {
4886       rtx set;
4887       enum machine_mode mode;
4888       int md_size;
4889       HOST_WIDE_INT pattern;
4890       int i;
4891
4892       if (GET_CODE (insn) != INSN)
4893         continue;
4894
4895       if (GET_CODE (PATTERN (insn)) == CONST_INT)
4896         {
4897           /* We've found a dummy expression.  */
4898           rtx remove_insn = insn;
4899           insn = prev_nonnote_insn (insn);
4900           delete_insn (remove_insn);
4901           continue;
4902         }
4903
4904       set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4905       if (set == NULL_RTX)
4906         continue;
4907
4908       mode = GET_MODE (XEXP (set, 0));
4909       md_size = GET_MODE_SIZE (mode);
4910       if ((md_size < 1) || (md_size > 4))
4911         continue;
4912
4913       pattern = 0;
4914       for (i = 0; i < md_size; i++)
4915         {
4916           pattern <<= 8;
4917           pattern |= 0xff;
4918         }
4919
4920       if ((GET_CODE (XEXP (set, 1)) == AND
4921            && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
4922            && INTVAL (XEXP (XEXP (set, 1), 1)) == pattern)
4923           || ((GET_CODE (XEXP (set, 1)) == IOR
4924                || GET_CODE (XEXP (set, 1)) == XOR)
4925               && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
4926               && INTVAL (XEXP (XEXP (set, 1), 1)) == 0x00))
4927         {
4928           /* We've found an AND with all 1's, an XOR with all 0's or an
4929              IOR with 0's.  */
4930           rtx remove_insn = insn;
4931
4932           /* Is it completely redundant or should it become a move insn?  */
4933           if (! rtx_equal_p (XEXP (set, 0), XEXP (XEXP (set, 1), 0)))
4934             {
4935               emit_insn_before (gen_rtx_SET (mode,
4936                                              XEXP (set, 0),
4937                                              XEXP (XEXP (set, 1), 0)),
4938                                 insn);
4939             }
4940
4941           insn = prev_nonnote_insn(insn);
4942           delete_insn (remove_insn);
4943         }
4944       else if (GET_CODE (XEXP (set, 1)) == AND
4945           && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
4946           && INTVAL (XEXP (XEXP (set, 1), 1)) == 0)
4947         {
4948           /* We've found an AND with all 0's.  */
4949           rtx remove_insn = insn;
4950           insn = emit_insn_before (gen_rtx_SET (mode,
4951                                                 XEXP (set, 0),
4952                                                 XEXP (XEXP (set, 1), 1)),
4953                                    insn);
4954           delete_insn (remove_insn);
4955         }
4956     }
4957 }
4958
4959 /* Structure used to track jump targets.  */
4960
4961 struct we_jump_targets
4962 {
4963   int target;                   /* Is this a jump target?  */
4964   int reach_count;              /* Number of ways we can reach this insn.  */
4965   int touch_count;              /* Number of times we've touched this insn
4966                                    during scanning.  */
4967   rtx w_equiv;                  /* WREG-equivalence at this point.  */
4968 };
4969
4970 struct we_jump_targets *ip2k_we_jump_targets;
4971
4972 /* WREG equivalence tracking used within DP reload elimination.  */
4973
4974 static int
4975 track_w_reload (insn, w_current, w_current_ok, modifying)
4976      rtx insn;
4977      rtx *w_current;
4978      int w_current_ok;
4979      int modifying;
4980 {
4981   rtx set;
4982
4983   if (GET_CODE (insn) != INSN)
4984     {
4985       *w_current = NULL_RTX;
4986       return 1;
4987     }
4988
4989   set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4990   if (set == NULL_RTX)
4991     {
4992       *w_current = NULL_RTX;
4993       return 1;
4994     }
4995
4996   /* Look for W being modified.  If it is, see if it's being changed
4997      to what it already is!  */
4998   if (GET_CODE (XEXP (set, 0)) == REG
4999       && REGNO (XEXP (set, 0)) == REG_W
5000       && GET_MODE (XEXP (set, 0)) == QImode)
5001     {
5002       /* If this is an equivalence we can delete the new set operation.  */
5003       if (*w_current != NULL_RTX
5004           && rtx_equal_p (XEXP (set, 1), *w_current))
5005         {
5006           if (modifying)
5007             delete_insn (insn);
5008         }
5009       else
5010         {
5011           *w_current = XEXP (set, 1);
5012           return 1;
5013         }
5014     }
5015   else if (recog_memoized (insn) < 0
5016            || get_attr_clobberw (insn) != CLOBBERW_NO)
5017     {
5018       /* If we clobber W then we've clobbered any equivalences !  */
5019       *w_current = NULL_RTX;
5020       return 1;
5021     }
5022   else if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2)
5023            && *w_current != NULL_RTX
5024            && !ip2k_xexp_not_uses_reg_p (*w_current, REG_SP, 2))
5025     {
5026       /* We look for a special case of "push" operations screwing up the
5027          setting of DP when it's based on the stack.  We can track this one
5028          and replace the old expression for DP with a new one.  */
5029       if (GET_CODE (XEXP (set, 0)) == MEM
5030           && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
5031           && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
5032           && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
5033           && GET_CODE (*w_current) == MEM
5034           && GET_CODE (XEXP (*w_current, 0)) == PLUS)
5035         {
5036           /* XXX - need to ensure that we can track this without going
5037              out of range!  */
5038           rtx val = GEN_INT (INTVAL (XEXP (XEXP (*w_current, 0), 1))
5039                              + GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
5040           *w_current
5041             = gen_rtx_MEM (HImode, gen_rtx_PLUS (Pmode,
5042                                                  gen_rtx_REG(HImode, REG_SP),
5043                                                  val));
5044           return 1;
5045         }
5046     }
5047   else if (GET_CODE (XEXP (set, 0)) == REG
5048            && *w_current != NULL_RTX
5049            && !ip2k_xexp_not_uses_reg_p (*w_current, REGNO (XEXP (set, 0)),
5050                                          GET_MODE_SIZE (GET_MODE (XEXP (set
5051                                                                         , 0)))))
5052     {
5053       /* If we've just clobbered all or part of a register reference that we
5054          were sharing for W then we can't share it any more!  */
5055       *w_current = NULL_RTX;
5056     }
5057
5058   return w_current_ok;
5059 }
5060
5061 /* As part of the machine-dependent reorg we scan moves into w and track them
5062    to see where any are redundant.  */
5063
5064 static void
5065 mdr_try_wreg_elim (first_insn)
5066      rtx first_insn;
5067 {
5068   rtx insn;
5069   struct we_jump_targets *wjt;
5070   rtx w_current;
5071   int incomplete_scan;
5072   int last_incomplete_scan;
5073
5074   ip2k_we_jump_targets
5075     = (struct we_jump_targets *) xcalloc (get_max_uid (),
5076                                           sizeof (struct we_jump_targets));
5077
5078   /* First we scan to build up a list of all CODE_LABEL insns and we work out
5079      how many different ways we can reach them.  */
5080   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5081     {
5082       if (GET_CODE (insn) == CODE_LABEL)
5083         {
5084           wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5085           wjt->target = 1;
5086           wjt->reach_count = LABEL_NUSES (insn);
5087           wjt->touch_count = 0;
5088           wjt->w_equiv = NULL_RTX;
5089           if (! prev_nonnote_insn (insn)
5090               || (prev_nonnote_insn (insn)
5091                   && GET_CODE (prev_nonnote_insn (insn)) != BARRIER))
5092             wjt->reach_count++;
5093         }
5094     }
5095
5096   /* Next we scan all of the ways of reaching the code labels to see
5097      what the WREG register is equivalent to as we reach them.  If we find
5098      that they're the same then we keep noting the matched value.  We
5099      iterate around this until we reach a convergence on WREG equivalences
5100      at all code labels - we have to be very careful not to be too
5101      optimistic!  */
5102   incomplete_scan = -1;
5103   do
5104     {
5105       int w_current_ok = 0;
5106       last_incomplete_scan = incomplete_scan;
5107       w_current = NULL_RTX;
5108
5109       for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5110         {
5111           /* If we have a code label then we need to see if we already know
5112              what the equivalence is at this point.  If we do then we use it
5113              immediately, but if we don't then we have a special case to track
5114              when we hit a fallthrough-edge (label with no barrier preceding
5115              it).  Any other accesses to the label must be from jump insns
5116              and so they're handled elsewhere.  */
5117           if (GET_CODE (insn) == CODE_LABEL)
5118             {
5119               wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5120
5121               /* If we're fully characterized the use the equivalence.  */
5122               if (wjt->touch_count == wjt->reach_count)
5123                 {
5124                   w_current = wjt->w_equiv;
5125                   w_current_ok = 1;
5126                   continue;
5127                 }
5128
5129               /* If we have a known equivalence for WREG as we reach the
5130                  fallthrough-edge then track this into the code label.  */
5131               if (w_current_ok
5132                   && (! prev_nonnote_insn (insn)
5133                       || (prev_nonnote_insn (insn)
5134                           && GET_CODE (prev_nonnote_insn (insn)) != BARRIER)))
5135                 {
5136                   if (wjt->touch_count == 0)
5137                     wjt->w_equiv = w_current;
5138
5139                   if (wjt->touch_count < wjt->reach_count)
5140                     {
5141                       wjt->touch_count++;
5142                       if (! rtx_equal_p (wjt->w_equiv, w_current))
5143                         {
5144                           /* When we definitely know that we can't form an
5145                              equivalence for WREG here we must clobber anything
5146                              that we'd started to track too.  */
5147                           wjt->w_equiv = NULL_RTX;
5148                           w_current = NULL_RTX;
5149                           w_current_ok = 1;
5150                         }
5151                     }
5152                 }
5153
5154               /* If we've not completely characterized this code label then
5155                  be cautious and assume that we don't know what WREG is
5156                  equivalent to.  */
5157               if (wjt->touch_count < wjt->reach_count)
5158                 {
5159                   w_current = NULL_RTX;
5160                   w_current_ok = 0;
5161                 }
5162
5163               continue;
5164             }
5165
5166           /* If we've hit a jump insn then we look for either an address
5167              vector (jump table) or for jump label references.  */
5168           if (GET_CODE (insn) == JUMP_INSN)
5169             {
5170               /* Don't attempt to track here if we don't have a known
5171                  equivalence for WREG at this point.  */
5172               if (w_current_ok)
5173                 {
5174                   if (JUMP_LABEL (insn))
5175                     {
5176                       wjt
5177                         = &ip2k_we_jump_targets[INSN_UID (JUMP_LABEL (insn))];
5178
5179                       if (wjt->touch_count == 0)
5180                         wjt->w_equiv = w_current;
5181
5182                       if (wjt->touch_count < wjt->reach_count)
5183                         {
5184                           wjt->touch_count++;
5185                           if (! rtx_equal_p (wjt->w_equiv, w_current))
5186                             wjt->w_equiv = NULL_RTX;
5187                         }
5188                     }
5189                 }
5190
5191               continue;
5192             }
5193
5194           /* Anything other than a code labal or jump arrives here.  We try and
5195              track WREG, but sometimes we might not be able to.  */
5196           w_current_ok = track_w_reload (insn, &w_current, w_current_ok, 0);
5197         }
5198
5199       /* When we're looking to see if we've finished we count the number of
5200          paths through the code labels where we weren't able to definitively
5201          track WREG.  This number is used to see if we're converging on a
5202          solution.
5203          If this hits zero then we've fully converged, but if this stays the
5204          same as last time then we probably can't make any further
5205          progress.  */
5206       incomplete_scan = 0;
5207       for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5208         {
5209           if (GET_CODE (insn) == CODE_LABEL)
5210             {
5211               wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5212               if (wjt->touch_count != wjt->reach_count)
5213                 {
5214                   incomplete_scan += (wjt->reach_count - wjt->touch_count);
5215                   wjt->w_equiv = NULL_RTX;
5216                   wjt->touch_count = 0;
5217                 }
5218             }
5219         }
5220     }
5221   while (incomplete_scan && incomplete_scan != last_incomplete_scan);
5222
5223   /* Finally we scan the whole function and run WREG elimination.  When we hit
5224      a CODE_LABEL we pick up any stored equivalence since we now know that
5225      every path to this point entered with WREG holding the same thing!  If
5226      we subsequently have a reload that matches then we can eliminate it.  */
5227   w_current = NULL_RTX;
5228   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5229     {
5230       if (GET_CODE (insn) == JUMP_INSN)
5231         continue;
5232
5233       if (GET_CODE (insn) == CODE_LABEL)
5234         {
5235           wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5236           w_current = wjt->w_equiv;
5237           continue;
5238         }
5239
5240       track_w_reload (insn, &w_current, 1, 1);
5241     }
5242
5243   free (ip2k_we_jump_targets);
5244 }
5245 #endif /* IP2K_MD_REORG_PASS */
5246
5247 /* We perform a lot of untangling of the RTL within the reorg pass since
5248    the IP2k requires some really bizarre (and really undesireable) things
5249    to happen in order to guarantee not aborting.  This pass causes several
5250    earlier passes to be re-run as it progressively transforms things,
5251    making the subsequent runs continue to win.  */
5252
5253 static void
5254 ip2k_reorg (void)
5255 {
5256 #ifdef IP2K_MD_REORG_PASS
5257   rtx first_insn, insn, set;
5258 #endif
5259
5260   CC_STATUS_INIT;
5261
5262   if (optimize == 0)
5263     {
5264       ip2k_reorg_completed = 1;
5265       ip2k_reorg_split_dimode = 1;
5266       ip2k_reorg_split_simode = 1;
5267       ip2k_reorg_split_himode = 1;
5268       ip2k_reorg_split_qimode = 1;
5269       ip2k_reorg_merge_qimode = 1;
5270       return;
5271     }
5272 #ifndef IP2K_MD_REORG_PASS
5273   ip2k_reorg_completed = 1;
5274   ip2k_reorg_split_dimode = 1;
5275   ip2k_reorg_split_simode = 1;
5276   ip2k_reorg_split_himode = 1;
5277   ip2k_reorg_split_qimode = 1;
5278   ip2k_reorg_merge_qimode = 1;
5279 #else
5280   /* All optimizations below must be debugged and enabled one by one.
5281      All of them commented now because of abort in GCC core.  */
5282   
5283   ip2k_reorg_in_progress = 1;
5284   
5285   first_insn = get_insns ();
5286
5287   /* Look for size effects of earlier optimizations - in particular look for
5288      situations where we're saying "use" a register on one hand but immediately
5289      tagging it as "REG_DEAD" at the same time!  Seems like a bug in core-gcc
5290      somewhere really but this is what we have to live with!  */
5291   for (insn = first_insn; insn; insn = NEXT_INSN (insn))
5292     {
5293       rtx body;
5294
5295       if (GET_CODE (insn) == CODE_LABEL
5296           || GET_CODE (insn) == NOTE
5297           || GET_CODE (insn) == BARRIER)
5298         continue;
5299
5300       if (!INSN_P (insn))
5301         continue;
5302
5303       body = PATTERN (insn);
5304       if (GET_CODE (body) == USE)
5305         if (GET_CODE (XEXP (body, 0)) == REG)
5306           {
5307             int reg;
5308
5309             reg = REGNO (XEXP (body, 0));
5310             if (find_regno_note (insn, REG_DEAD, reg))
5311               {
5312                 delete_insn (insn);
5313               }
5314           }
5315     }
5316
5317   /* There's a good chance that since we last did CSE that we've rearranged
5318      things in such a way that another go will win.  Do so now!  */
5319   reload_cse_regs (first_insn);
5320   find_basic_blocks (first_insn, max_reg_num (), 0);
5321   life_analysis (0, PROP_REG_INFO | PROP_DEATH_NOTES);
5322   
5323   /* Look for where absurd things are happening with DP.  */
5324   mdr_try_dp_reload_elim (first_insn);
5325
5326   ip2k_reorg_in_progress = 0;
5327   ip2k_reorg_completed = 1;
5328
5329   split_all_insns (0);
5330
5331   reload_cse_regs (first_insn);
5332   find_basic_blocks (first_insn, max_reg_num (), 0);
5333   life_analysis (0, PROP_REG_INFO | PROP_DEATH_NOTES);
5334   if (flag_peephole2)
5335     peephole2_optimize (NULL);
5336
5337   mdr_resequence_xy_yx (first_insn);
5338   mdr_propagate_reg_equivs (first_insn);
5339
5340   /* Look for redundant set instructions.  These can occur when we split
5341      instruction patterns and end up with the second half merging with
5342      or being replaced by something that clobbers the first half.  */
5343   for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5344     {
5345       if (GET_CODE (insn) == INSN)
5346         {
5347           set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
5348           if ((set != NULL_RTX)
5349               && (GET_CODE (XEXP (set, 0)) == REG)
5350               && (GET_MODE (XEXP (set, 0)) == QImode)
5351               && (find_regno_note (insn, REG_UNUSED, REGNO (XEXP (set, 0)))))
5352             delete_insn (insn);
5353         }
5354     }
5355
5356   mdr_try_move_dp_reload (first_insn);
5357   mdr_try_move_pushes (first_insn);
5358
5359   find_basic_blocks (first_insn, max_reg_num (), 0);
5360   life_analysis (0, PROP_FINAL);
5361
5362   mdr_try_propagate_move (first_insn);
5363   mdr_resequence_xy_yx (first_insn);
5364
5365   ip2k_reorg_split_dimode = 1;
5366   split_all_insns (0);
5367
5368   mdr_try_remove_redundant_insns (first_insn);
5369
5370   mdr_try_propagate_move (first_insn);
5371
5372   reload_cse_regs (first_insn);
5373   find_basic_blocks (first_insn, max_reg_num (), 0);
5374   life_analysis (0, PROP_FINAL);
5375   if (flag_peephole2)
5376     peephole2_optimize (NULL);
5377
5378   mdr_try_propagate_move (first_insn);
5379
5380   find_basic_blocks (first_insn, max_reg_num (), 0);
5381   life_analysis (0, PROP_FINAL);
5382
5383   ip2k_reorg_split_simode = 1;
5384   split_all_insns (0);
5385
5386   mdr_try_remove_redundant_insns (first_insn);
5387
5388   mdr_try_propagate_move (first_insn);
5389
5390   reload_cse_regs (first_insn);
5391   find_basic_blocks (first_insn, max_reg_num (), 0);
5392   life_analysis (0, PROP_FINAL);
5393   if (flag_peephole2)
5394     peephole2_optimize (NULL);
5395
5396   mdr_try_propagate_move (first_insn);
5397
5398   find_basic_blocks (first_insn, max_reg_num (), 0);
5399   life_analysis (0, PROP_FINAL);
5400
5401   ip2k_reorg_split_himode = 1;
5402   ip2k_reorg_merge_qimode = 1;
5403   split_all_insns (0);
5404
5405   mdr_try_remove_redundant_insns (first_insn);
5406   mdr_try_propagate_clr (first_insn);
5407   mdr_try_propagate_move (first_insn);
5408
5409   mdr_try_dp_reload_elim (first_insn);
5410   mdr_try_move_dp_reload (first_insn);
5411
5412   rebuild_jump_labels (first_insn);
5413
5414   /* Call to  jump_optimize (...) was here, but now I removed it.  */
5415   
5416   find_basic_blocks (first_insn, max_reg_num (), 0);
5417   life_analysis (0, PROP_FINAL);
5418   if (flag_peephole2)
5419     peephole2_optimize (NULL);
5420
5421   mdr_try_propagate_move (first_insn);
5422
5423   find_basic_blocks (first_insn, max_reg_num (), 0);
5424   life_analysis (0, PROP_FINAL);
5425   mdr_try_remove_redundant_insns (first_insn);
5426
5427   mdr_try_propagate_clr (first_insn);
5428   mdr_try_propagate_move (first_insn);
5429
5430   find_basic_blocks (first_insn, max_reg_num (), 0);
5431   life_analysis (0, PROP_FINAL);
5432
5433   ip2k_reorg_split_qimode = 1;
5434   split_all_insns (0);
5435
5436   mdr_try_wreg_elim (first_insn);
5437   mdr_try_propagate_move (first_insn);
5438
5439   find_basic_blocks (first_insn, max_reg_num (), 0);
5440   life_analysis (0, PROP_FINAL);
5441 #endif
5442 }
5443
5444 static void
5445 ip2k_init_libfuncs (void)
5446 {
5447   set_optab_libfunc (smul_optab, SImode, "_mulsi3");
5448   set_optab_libfunc (smul_optab, DImode, "_muldi3");
5449   set_optab_libfunc (cmp_optab,  HImode, "_cmphi2");
5450   set_optab_libfunc (cmp_optab,  SImode, "_cmpsi2");
5451 }
5452
5453 /* Returns a bit position if mask contains only a single bit.  Returns -1 if
5454    there were zero or more than one set bits.  */
5455 int
5456 find_one_set_bit_p (HOST_WIDE_INT mask)
5457 {
5458   int i;
5459   unsigned HOST_WIDE_INT n = mask;
5460   for (i = 0; i < 32; i++)
5461     {
5462       if (n & 0x80000000UL)
5463         {
5464           if (n & 0x7fffffffUL)
5465             return -1;
5466           else
5467             return 31 - i;
5468         }
5469       n <<= 1;
5470     }
5471   return -1;
5472 }
5473
5474 /* Returns a bit position if mask contains only a single clear bit.
5475    Returns -1 if there were zero or more than one clear bits.  */
5476 int
5477 find_one_clear_bit_p (HOST_WIDE_INT mask)
5478 {
5479   int i;
5480   unsigned HOST_WIDE_INT n = mask;
5481   for (i = 0; i < 32; i++)
5482     {
5483       if ((n & 0x80000000UL) == 0UL)
5484         {
5485           if ((n & 0x7fffffffUL) != 0x7fffffffUL)
5486             return -1;
5487           else
5488             return 31 - i;
5489         }
5490       n <<= 1;
5491       n |= 1;
5492     }
5493   return -1;
5494 }
5495
5496 \f
5497 /* Split a move into two smaller pieces.
5498    MODE indicates the reduced mode.  OPERANDS[0] is the original destination
5499    OPERANDS[1] is the original src.  The new destinations are
5500    OPERANDS[2] and OPERANDS[4], while the new sources are OPERANDS[3]
5501    and OPERANDS[5].  */
5502
5503 void
5504 ip2k_split_words (enum machine_mode nmode, enum machine_mode omode,
5505                   rtx *operands)
5506 {
5507   rtx dl, dh;                   /* src/dest pieces.  */
5508   rtx sl, sh;
5509   int move_high_first = 0;      /* Assume no overlap.  */
5510   int pushflag = 0;
5511
5512   switch (GET_CODE (operands[0])) /* DEST */
5513     {
5514     case SUBREG:
5515     case REG:
5516       if ((GET_CODE (operands[1]) == REG
5517            || GET_CODE (operands[1]) == SUBREG)
5518           && (true_regnum (operands[0]) <= true_regnum (operands[1])
5519               || (true_regnum (operands[1])
5520                   + GET_MODE_SIZE (omode) - 1 < true_regnum (operands[0]))))
5521         move_high_first = 1;
5522
5523       if (GET_CODE (operands[0]) == SUBREG)
5524         {
5525           dl = simplify_gen_subreg (nmode, operands[0], omode,
5526                                     GET_MODE_SIZE (nmode));
5527           dh = simplify_gen_subreg (nmode, operands[0], omode, 0);
5528         }
5529       else if (GET_CODE (operands[0]) == REG && ! IS_PSEUDO_P (operands[0]))
5530         {
5531           int   r = REGNO (operands[0]);
5532           dh = gen_rtx_REG (nmode, r);
5533           dl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
5534         }
5535       else
5536         {
5537           dh = gen_rtx_SUBREG (nmode, operands[0], 0);
5538           dl = gen_rtx_SUBREG (nmode, operands[0], GET_MODE_SIZE (nmode));
5539         }
5540       break;
5541
5542     case MEM:
5543       switch (GET_CODE (XEXP (operands[0], 0)))
5544         {
5545         case POST_INC:
5546           abort ();
5547         case POST_DEC:
5548           dl = dh = gen_rtx_MEM (nmode, XEXP (operands[0], 0));
5549           pushflag = 1;
5550           break;
5551         default:
5552           dl = change_address (operands[0], nmode,
5553                                plus_constant (XEXP (operands[0], 0),
5554                                               GET_MODE_SIZE (nmode)));
5555           dh = gen_rtx_MEM (nmode, XEXP (operands[0], 0));
5556         }
5557       break;
5558     default:
5559       abort ();
5560     }
5561
5562   switch (GET_CODE (operands[1]))
5563     {
5564     case REG:
5565       if (! IS_PSEUDO_P (operands[1]))
5566         {
5567           int r = REGNO (operands[1]);
5568
5569           sh = gen_rtx_REG (nmode, r);
5570           sl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
5571         }
5572       else
5573         {
5574           sh = gen_rtx_SUBREG (nmode, operands[1], 0);
5575           sl = gen_rtx_SUBREG (nmode, operands[1], GET_MODE_SIZE (nmode));
5576         }
5577       break;
5578
5579     case CONST_DOUBLE:
5580       if (operands[1] == const0_rtx)
5581         sh = sl = const0_rtx;
5582       else
5583         {
5584           if (GET_MODE (operands[0]) != DImode)
5585             {
5586               REAL_VALUE_TYPE rv;
5587               long value;
5588
5589               REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
5590               REAL_VALUE_TO_TARGET_SINGLE (rv, value);
5591
5592               sh = gen_int_mode ((value >> 16) & 0xffff, nmode);
5593               sl = gen_int_mode (value & 0xffff, nmode);
5594             }
5595           else
5596             {
5597               sh = gen_int_mode (CONST_DOUBLE_HIGH (operands[1]), nmode);
5598               sl = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), nmode);
5599             }
5600         }
5601       break;
5602
5603     case CONST_INT:
5604       if (operands[1] == const0_rtx)
5605         sh = sl = const0_rtx;
5606       else
5607         {
5608           int val = INTVAL (operands[1]);
5609           int vl, vh;
5610
5611           switch (nmode)
5612             {
5613             case QImode:
5614               vh = (val >> 8) & 0xff;
5615               vl = val & 0xff;
5616               break;
5617
5618             case HImode:
5619               vh = (val >> 16) & 0xffff;
5620               vl = val & 0xffff;
5621               break;
5622
5623             case SImode:
5624               if (val < 0)      /* sign extend  */
5625                 vh = -1;
5626               else
5627                 vh = 0;
5628               vl = val;         /* Give low 32 bits back.  */
5629               break;
5630
5631             default:
5632               abort ();
5633             }
5634             
5635           sl = gen_int_mode (vl, nmode);
5636           sh = gen_int_mode (vh, nmode);
5637         }
5638       break;
5639
5640     case SUBREG:
5641       sl = simplify_gen_subreg (nmode, operands[1], omode,
5642                                 GET_MODE_SIZE (nmode));
5643       sh = simplify_gen_subreg (nmode, operands[1], omode, 0);
5644       break;
5645
5646     case MEM:
5647       switch (GET_CODE (XEXP (operands[1], 0)))
5648         {
5649         case POST_DEC:
5650         case POST_INC:
5651           abort ();
5652           break;
5653
5654         default:
5655           /* Worry about splitting stack pushes.  */
5656           if (pushflag && ip2k_address_uses_reg_p (operands[1], REG_SP))
5657             sl = sh = change_address (operands[1], nmode,
5658                                       plus_constant (XEXP (operands[1], 0),
5659                                                      GET_MODE_SIZE (nmode)));
5660           else
5661             {
5662               sl = change_address (operands[1], nmode,
5663                                    plus_constant (XEXP (operands[1], 0),
5664                                                   GET_MODE_SIZE (nmode)));
5665               sh = gen_rtx_MEM (nmode, XEXP (operands[1], 0));
5666             }
5667         }
5668       break;
5669
5670     default:
5671       abort ();
5672     }
5673
5674   if (move_high_first)
5675     {
5676       operands[2] = dh;
5677       operands[3] = sh;
5678       operands[4] = dl;
5679       operands[5] = sl;
5680     }
5681   else
5682     {
5683       operands[2] = dl;
5684       operands[3] = sl;
5685       operands[4] = dh;
5686       operands[5] = sh;
5687     }
5688   return;
5689 }
5690
5691 /* Get the low half of an operand.  */
5692 rtx
5693 ip2k_get_low_half (rtx x, enum machine_mode mode)
5694 {
5695   switch (GET_CODE (x))
5696     {
5697     case REG:
5698       if (! IS_PSEUDO_P (x))
5699         {
5700           unsigned int r = REGNO (x);
5701
5702           return gen_rtx_REG (mode, r + HARD_REGNO_NREGS (r, mode));
5703         }
5704       else
5705         {
5706           return gen_rtx_SUBREG (mode, x, GET_MODE_SIZE (mode));
5707         }
5708       break;
5709
5710     case CONST_DOUBLE:
5711       if (x == const0_rtx)
5712         return const0_rtx;
5713       else
5714         {
5715           if (mode != SImode)
5716             {
5717               REAL_VALUE_TYPE rv;
5718               long value;
5719
5720               REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
5721               REAL_VALUE_TO_TARGET_SINGLE (rv, value);
5722
5723               return gen_int_mode (value & 0xffff, mode);
5724             }
5725           else
5726             return gen_int_mode (CONST_DOUBLE_LOW (x), mode);
5727         }
5728       break;
5729
5730     case CONST_INT:
5731       if (x == const0_rtx)
5732         return const0_rtx;
5733       else
5734         {
5735           int val = INTVAL (x);
5736           int vl, vh;
5737
5738           switch (mode)
5739             {
5740             case QImode:
5741               vh = (val >> 8) & 0xff;
5742               vl = val & 0xff;
5743               break;
5744
5745             case HImode:
5746               vh = (val >> 16) & 0xffff;
5747               vl = val & 0xffff;
5748               break;
5749
5750             case SImode:
5751               if (val < 0)      /* sign extend */
5752                 vh = -1;
5753               else
5754                 vh = 0;
5755               vl = val;         /* Give low 32 bits back.  */
5756               break;
5757
5758             default:
5759               abort ();
5760             }
5761             
5762           return gen_int_mode (vl, mode);
5763         }
5764       break;
5765
5766     case SUBREG:
5767       return simplify_gen_subreg (mode, x, GET_MODE (x), GET_MODE_SIZE (mode));
5768
5769     case MEM:
5770       switch (GET_CODE (XEXP (x, 0)))
5771         {
5772         case POST_DEC:
5773         case POST_INC:
5774           abort ();
5775           break;
5776
5777         default:
5778           return change_address (x, mode,
5779                                  plus_constant (XEXP (x, 0),
5780                                                 GET_MODE_SIZE (mode)));
5781         }
5782       break;
5783
5784     default:
5785       abort ();
5786     }
5787   return NULL_RTX;
5788 }
5789
5790 /* Get the high half of an operand.  */
5791 rtx
5792 ip2k_get_high_half (rtx x, enum machine_mode mode)
5793 {
5794   switch (GET_CODE (x))
5795     {
5796     case REG:
5797       if (! IS_PSEUDO_P (x))
5798         {
5799           unsigned int r = REGNO (x);
5800
5801           return gen_rtx_REG (mode, r);
5802         }
5803       else
5804         {
5805           return gen_rtx_SUBREG (mode, x, 0);
5806         }
5807       break;
5808
5809     case CONST_DOUBLE:
5810       if (x == const0_rtx)
5811         return const0_rtx;
5812       else
5813         {
5814           if (mode != SImode)
5815             {
5816               REAL_VALUE_TYPE rv;
5817               long value;
5818
5819               REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
5820               REAL_VALUE_TO_TARGET_SINGLE (rv, value);
5821
5822               return gen_int_mode ((value >> 16) & 0xffff, mode);
5823             }
5824           else
5825             return gen_int_mode (CONST_DOUBLE_HIGH (x), mode);
5826         }
5827       break;
5828
5829     case CONST_INT:
5830       if (x == const0_rtx)
5831         return const0_rtx;
5832       else
5833         {
5834           int val = INTVAL (x);
5835           int vl, vh;
5836
5837           switch (mode)
5838           {
5839             case QImode:
5840               vh = (val >> 8) & 0xff;
5841               vl = val & 0xff;
5842               break;
5843
5844             case HImode:
5845               vh = (val >> 16) & 0xffff;
5846               vl = val & 0xffff;
5847               break;
5848
5849             case SImode:
5850               if (val < 0)      /* sign extend */
5851                 vh = -1;
5852               else
5853                 vh = 0;
5854               vl = val;         /* Give low 32 bits back.  */
5855               break;
5856
5857             default:
5858               abort ();
5859             }
5860             
5861           return gen_int_mode (vh, mode);
5862         }
5863       break;
5864
5865     case SUBREG:
5866       return simplify_gen_subreg (mode, x, GET_MODE (x), 0);
5867       break;
5868
5869     case MEM:
5870       switch (GET_CODE (XEXP (x, 0)))
5871         {
5872         case POST_DEC:
5873         case POST_INC:
5874           abort ();
5875           break;
5876
5877         default:
5878           return change_address (x, mode, plus_constant (XEXP (x, 0), 0));
5879         }
5880       break;
5881
5882     default:
5883       abort ();
5884     }
5885   return NULL_RTX;
5886 }
5887
5888 /* Does address X use register R. Only valid for REG_SP, REG_DP, REG_IP
5889    or REG_FP.  */
5890
5891 int
5892 ip2k_address_uses_reg_p (rtx x, unsigned int r)
5893 {
5894   if (GET_CODE (x) != MEM)
5895     return 0;
5896
5897   x = XEXP (x, 0);
5898
5899   while (1)
5900     switch (GET_CODE (x))
5901       {
5902       case POST_DEC:
5903       case POST_INC:
5904       case PRE_DEC:
5905       case PRE_INC:
5906         x = XEXP (x, 0);
5907         break;
5908
5909       case PLUS:
5910         if (ip2k_address_uses_reg_p (XEXP (x, 1), r))
5911           return 1;
5912
5913         x = XEXP (x, 0);
5914         break;
5915
5916       case SUBREG:
5917         /* Ignore subwords.  */
5918         x = SUBREG_REG (x);
5919         break;
5920
5921       case REG:
5922         /* Have to consider that r might be LSB of a pointer reg.  */
5923         return ((REGNO (x) == r) || (REGNO (x) == (r - 1))) ? 1 : 0;
5924
5925       case MEM:
5926         /* We might be looking at a (mem:BLK (mem (...)))  */
5927         x = XEXP (x, 0);
5928         break;
5929
5930       default:
5931         return 0;
5932       };
5933 }
5934
5935 /* Does the queried XEXP not use a particular register?  If we're certain
5936    that it doesn't then we return TRUE otherwise we assume FALSE.  */
5937
5938 int
5939 ip2k_xexp_not_uses_reg_p (rtx x, unsigned int r, int rsz)
5940 {
5941   switch (GET_CODE (x))
5942     {
5943     case REG:
5944       {
5945         int msz = GET_MODE_SIZE (GET_MODE (x));
5946
5947         return (((REGNO (x) + msz - 1) < r)
5948                 || (REGNO (x) > (r + rsz - 1)));
5949       }
5950
5951     case MEM:
5952       return !ip2k_address_uses_reg_p (x, r);
5953
5954     case LABEL_REF:
5955     case SYMBOL_REF:
5956     case CONST:
5957     case CONST_INT:
5958     case CONST_DOUBLE:
5959     case CC0:
5960     case PC:
5961       return 1;
5962
5963     default:
5964       return 0;
5965     }
5966 }
5967
5968 /* Does the queried XEXP not use a particular register?  If we're certain
5969    that it doesn't then we return TRUE otherwise we assume FALSE.  */
5970
5971 int
5972 ip2k_composite_xexp_not_uses_reg_p (rtx x, unsigned int r, int rsz)
5973 {
5974   if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS)
5975     return (ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz)
5976             && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 1), r, rsz)
5977             && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 2), r, rsz));
5978
5979   if (BINARY_P (x))
5980     return (ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz)
5981             && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 1), r, rsz));
5982
5983   if (UNARY_P (x)
5984       || GET_RTX_CLASS (GET_CODE (x)) == RTX_TERNARY)
5985     return ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz);
5986
5987   return ip2k_xexp_not_uses_reg_p (x, r, rsz);
5988 }
5989
5990 /* Does the queried XEXP not use CC0?  If we're certain that
5991    it doesn't then we return TRUE otherwise we assume FALSE.  */
5992
5993 int
5994 ip2k_composite_xexp_not_uses_cc0_p (rtx x)
5995 {
5996   if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS)
5997     return (ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0))
5998             && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 1))
5999             && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 2)));
6000
6001   if (BINARY_P (x))
6002     return (ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0))
6003             && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 1)));
6004
6005   if (UNARY_P (x)
6006       || GET_RTX_CLASS (GET_CODE (x)) == RTX_TERNARY)
6007     return ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0));
6008
6009   return GET_CODE (x) != CC0;
6010 }
6011
6012 int
6013 ip2k_split_dest_operand (rtx x, enum machine_mode mode)
6014 {
6015   return nonimmediate_operand (x, mode) || push_operand (x, mode);
6016 }
6017
6018 int
6019 ip2k_nonptr_operand (rtx x, enum machine_mode mode)
6020 {
6021   return register_operand (x, mode) && !ip2k_ptr_operand (x, mode);
6022 }
6023
6024 /* Is X a reference to IP or DP or SP?  */
6025
6026 int
6027 ip2k_ptr_operand (rtx x, enum machine_mode mode)
6028
6029 {
6030   if (GET_CODE (x) == SUBREG)
6031     x = SUBREG_REG (x);
6032
6033   return (REG_P (x)
6034           && (mode == HImode || mode == VOIDmode)
6035           && (REGNO (x) == REG_IP
6036               || REGNO (x) == REG_DP
6037               || REGNO (x) == REG_SP));
6038 }
6039
6040 int
6041 ip2k_sp_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
6042
6043 {
6044   return REG_P (x) && REGNO (x) == REG_SP;
6045 }
6046
6047 int
6048 ip2k_ip_operand (rtx x, enum machine_mode mode)
6049
6050 {
6051   if (GET_CODE (x) != MEM)
6052     return 0;
6053
6054   x = XEXP (x, 0);
6055
6056   if (GET_CODE (x) == PLUS && XEXP (x, 1) == const0_rtx)
6057     x = XEXP (x, 0);
6058
6059   if (! REG_P (x))
6060     return 0;
6061
6062   if (GET_MODE_SIZE (mode) > 1)
6063     return 0;                   /* Can't access offset bytes.  */
6064
6065   return REGNO (x) == REG_IP;
6066 }
6067
6068 /* Is X a memory address suitable for SP or DP relative addressing?  */
6069 int
6070 ip2k_short_operand (rtx x, enum machine_mode mode)
6071 {
6072   int r;
6073   unsigned int offs = 0;
6074
6075   if (! memory_operand (x, mode))
6076     return 0;                   /* Got to be a memory address.  */
6077
6078   x = XEXP (x, 0);
6079   switch (GET_CODE (x))
6080     {
6081     default:
6082       return 0;
6083
6084     case PLUS:
6085       if (! REG_P (XEXP (x, 0))
6086           || GET_CODE (XEXP (x, 1)) != CONST_INT)
6087         return 0;
6088
6089       offs = INTVAL (XEXP (x, 1));
6090
6091       if (128 <= offs)
6092         return 0;
6093
6094       x = XEXP (x, 0);
6095
6096       /* fall through  */
6097
6098     case REG:
6099       if (IS_PSEUDO_P (x))
6100         return 0;               /* Optimistic - doesn't work.  */
6101
6102       r = REGNO (x);
6103
6104       /* For 'S' constraint, we presume that no IP adjustment
6105          simulation is performed - so only QI mode allows IP to be a
6106          short offset address.  All other IP references must be
6107          handled by 'R' constraints.  */
6108       if (r == REG_IP && offs == 0 && GET_MODE_SIZE (mode) <= 1)
6109         return 1;
6110
6111       return (r == REG_SP || r == REG_DP);
6112     }
6113 }
6114
6115 int
6116 ip2k_nonsp_reg_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
6117 {
6118   if (GET_CODE (x) == SUBREG)
6119     x = SUBREG_REG (x);
6120
6121   return (REG_P (x) && REGNO (x) != REG_SP);
6122 }
6123
6124 int
6125 ip2k_gen_operand (rtx x, enum machine_mode mode)
6126 {
6127   return ip2k_short_operand (x, mode)
6128     || (GET_CODE (x) == SUBREG
6129         && REG_P (SUBREG_REG (x)))
6130     || (ip2k_nonsp_reg_operand (x, mode));
6131 }
6132
6133 int
6134 ip2k_extra_constraint (rtx x, int c)
6135
6136   switch (c)
6137     {
6138     case 'S':                   /* Allow offset in stack frame...  */
6139       return ip2k_short_operand (x, GET_MODE (x));
6140
6141     case 'R':
6142       return ip2k_ip_operand (x, GET_MODE (x));
6143
6144     case 'T':                   /* Constant int or .data address.  */
6145       return CONSTANT_P (x) && is_regfile_address (x);
6146
6147     default:
6148       return 0;
6149     }
6150 }
6151
6152 int
6153 ip2k_unary_operator (rtx op, enum machine_mode mode)
6154 {
6155   return ((mode == VOIDmode || GET_MODE (op) == mode)
6156           && UNARY_P (op));
6157 }
6158
6159 int
6160 ip2k_binary_operator (rtx op, enum machine_mode mode)
6161 {
6162   return ((mode == VOIDmode || GET_MODE (op) == mode)
6163           && ARITHMETIC_P (op));
6164 }
6165
6166 int
6167 ip2k_symbol_ref_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
6168 {
6169   /* We define an IP2k symbol ref to be either a direct reference or one
6170      with a constant offset.  */
6171   return (GET_CODE (op) == SYMBOL_REF)
6172          || (GET_CODE (op) == CONST
6173              && GET_CODE (XEXP (op, 0)) == PLUS
6174              && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF);
6175 }
6176
6177 int
6178 ip2k_signed_comparison_operator (rtx op, enum machine_mode mode)
6179 {
6180   return (comparison_operator (op, mode)
6181     && signed_condition (GET_CODE (op)) == GET_CODE (op));
6182 }
6183
6184 int
6185 ip2k_unsigned_comparison_operator (rtx op, enum machine_mode mode)
6186 {
6187   return (comparison_operator (op, mode)
6188           && unsigned_condition (GET_CODE (op)) == GET_CODE (op));
6189 }
6190
6191 /* Worker function for TARGET_RETURN_IN_MEMORY.  */
6192
6193 static bool
6194 ip2k_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
6195 {
6196   if (TYPE_MODE (type) == BLKmode)
6197     {
6198       HOST_WIDE_INT size = int_size_in_bytes (type);
6199       return (size == -1 || size > 8);
6200     }
6201   else
6202     return false;
6203 }
6204
6205 /* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
6206
6207 static void
6208 ip2k_setup_incoming_varargs (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
6209                              enum machine_mode mode ATTRIBUTE_UNUSED,
6210                              tree type ATTRIBUTE_UNUSED,
6211                              int *pretend_arg_size,
6212                              int second_time ATTRIBUTE_UNUSED)
6213 {
6214   *pretend_arg_size = 0;
6215 }