OSDN Git Service

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