OSDN Git Service

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