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