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