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