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