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