* common.opt (-Wattributes): New. Default true.
[official-gcc.git] / gcc / config / ip2k / ip2k.c
blob7542b46b6fead7f6a19a8a18ac7aabe76c15d023
1 /* Subroutines used for code generation on Ubicom IP2022
2 Communications Controller.
3 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
4 Free Software Foundation, Inc.
5 Contributed by Red Hat, Inc and Ubicom, Inc.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
14 GCC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "tm.h"
28 #include "rtl.h"
29 #include "regs.h"
30 #include "hard-reg-set.h"
31 #include "real.h"
32 #include "insn-config.h"
33 #include "conditions.h"
34 #include "insn-flags.h"
35 #include "output.h"
36 #include "insn-attr.h"
37 #include "insn-addr.h"
38 #include "flags.h"
39 #include "reload.h"
40 #include "tree.h"
41 #include "expr.h"
42 #include "optabs.h"
43 #include "toplev.h"
44 #include "obstack.h"
45 #include "function.h"
46 #include "recog.h"
47 #include "tm_p.h"
48 #include "target.h"
49 #include "target-def.h"
50 #include "basic-block.h"
52 /* There are problems with 'frame_pointer_needed'. If we force it
53 on, we either end up not eliminating uses of FP, which results in
54 SPILL register failures or we may end up with calculation errors in
55 the stack offsets. Isolate the decision process into a simple macro. */
56 #define CHAIN_FRAMES (frame_pointer_needed || FRAME_POINTER_REQUIRED)
58 static int ip2k_naked_function_p (tree);
59 #ifdef IP2K_MD_REORG_PASS
60 static void mdr_resequence_xy_yx (rtx);
61 static void mdr_pres_replace_and_recurse (rtx, rtx, rtx);
62 static void mdr_propagate_reg_equivs_sequence (rtx, rtx, rtx);
63 static void mdr_propagate_reg_equivs (rtx);
64 static int track_dp_reload (rtx , rtx *, int , int);
65 static void mdr_try_dp_reload_elim (rtx);
66 static void mdr_try_move_dp_reload (rtx);
67 static void mdr_try_move_pushes (rtx);
68 static void mdr_try_propagate_clr_sequence (rtx, unsigned int);
69 static void mdr_try_propagate_clr (rtx);
70 static void mdr_try_propagate_move_sequence (rtx, rtx, rtx);
71 static void mdr_try_propagate_move (rtx);
72 static void mdr_try_remove_redundant_insns (rtx);
73 static int track_w_reload (rtx, rtx *, int , int);
74 static void mdr_try_wreg_elim (rtx);
75 #endif /* IP2K_MD_REORG_PASS */
76 static void ip2k_reorg (void);
77 static int ip2k_check_can_adjust_stack_ref (rtx, int);
78 static void ip2k_adjust_stack_ref (rtx *, int);
79 static int ip2k_xexp_not_uses_reg_for_mem (rtx, unsigned int);
80 static tree ip2k_handle_progmem_attribute (tree *, tree, tree, int, bool *);
81 static tree ip2k_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
82 static bool ip2k_rtx_costs (rtx, int, int, int *);
83 static int ip2k_address_cost (rtx);
84 static void ip2k_init_libfuncs (void);
85 static bool ip2k_return_in_memory (tree, tree);
86 static void ip2k_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
87 tree, int *, int);
89 const struct attribute_spec ip2k_attribute_table[];
92 /* Initialize the GCC target structure. */
93 #undef TARGET_ASM_ALIGNED_HI_OP
94 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
96 #undef TARGET_ASM_FUNCTION_PROLOGUE
97 #define TARGET_ASM_FUNCTION_PROLOGUE function_prologue
99 #undef TARGET_ASM_FUNCTION_EPILOGUE
100 #define TARGET_ASM_FUNCTION_EPILOGUE function_epilogue
102 #undef TARGET_ASM_UNIQUE_SECTION
103 #define TARGET_ASM_UNIQUE_SECTION unique_section
105 #undef TARGET_ASM_FUNCTION_RODATA_SECTION
106 #define TARGET_ASM_FUNCTION_RODATA_SECTION default_no_function_rodata_section
108 #undef TARGET_ATTRIBUTE_TABLE
109 #define TARGET_ATTRIBUTE_TABLE ip2k_attribute_table
111 #undef TARGET_RTX_COSTS
112 #define TARGET_RTX_COSTS ip2k_rtx_costs
113 #undef TARGET_ADDRESS_COST
114 #define TARGET_ADDRESS_COST ip2k_address_cost
116 #undef TARGET_MACHINE_DEPENDENT_REORG
117 #define TARGET_MACHINE_DEPENDENT_REORG ip2k_reorg
119 #undef TARGET_INIT_LIBFUNCS
120 #define TARGET_INIT_LIBFUNCS ip2k_init_libfuncs
122 #undef TARGET_RETURN_IN_MEMORY
123 #define TARGET_RETURN_IN_MEMORY ip2k_return_in_memory
125 #undef TARGET_SETUP_INCOMING_VARARGS
126 #define TARGET_SETUP_INCOMING_VARARGS ip2k_setup_incoming_varargs
128 struct gcc_target targetm = TARGET_INITIALIZER;
130 /* Prologue/Epilogue size in words. */
131 static int prologue_size;
132 static int epilogue_size;
134 /* compare and test instructions for the IP2K are materialized by
135 the conditional branch that uses them. This is because conditional
136 branches are skips over unconditional branches. */
137 rtx ip2k_compare_operands[3]; /* Additional operands for condition code. */
138 int ip2k_test_flag; /* Indicates Z, WREG contain condition code
139 information. */
141 /* Some ip2k patterns push a byte onto the stack and then access
142 SP-relative addresses. Since reload doesn't know about these
143 pushes, we must track them internally with a %< (push) or %> (pop)
144 indicator. */
145 static int ip2k_stack_delta;
147 /* Track if or how far our ip2k reorganization pass has run. */
148 int ip2k_reorg_in_progress = 0;
149 int ip2k_reorg_completed = 0;
150 int ip2k_reorg_split_dimode = 0;
151 int ip2k_reorg_split_simode = 0;
152 int ip2k_reorg_split_himode = 0;
153 int ip2k_reorg_split_qimode = 0;
154 int ip2k_reorg_merge_qimode = 0;
156 /* Set up local allocation order. */
158 void
159 ip2k_init_local_alloc (int *rao)
161 static const int alloc_order[] = REG_ALLOC_ORDER;
163 memcpy (rao, alloc_order, sizeof (alloc_order));
166 /* Returns the number of bytes of arguments automatically
167 popped when returning from a subroutine call.
168 FUNDECL is the declaration node of the function (as a tree),
169 FUNTYPE is the data type of the function (as a tree),
170 or for a library call it is an identifier node for the subroutine name.
171 SIZE is the number of bytes of arguments passed on the stack. */
174 ip2k_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size)
176 if (TREE_CODE (funtype) == IDENTIFIER_NODE)
177 return size;
179 if (TYPE_ARG_TYPES (funtype) == NULL_TREE
180 || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
181 return size;
183 return 0;
186 /* Return nonzero if FUNC is a naked function. */
188 static int
189 ip2k_naked_function_p (tree func)
191 tree a;
193 if (TREE_CODE (func) != FUNCTION_DECL)
194 abort ();
196 a = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
197 return a != NULL_TREE;
200 /* Output function prologue. */
201 void
202 function_prologue (FILE *file, HOST_WIDE_INT size)
204 int leaf_func_p;
205 int main_p;
206 int reg;
207 rtx operands[2];
209 prologue_size = epilogue_size = 0;
211 if (ip2k_naked_function_p (current_function_decl))
213 fprintf (file, "/* prologue: naked */\n");
214 return;
217 leaf_func_p = leaf_function_p ();
218 main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
220 /* For now, we compute all these facts about the function, but don't
221 take any action based on the information. */
223 prologue_size = 0;
224 fprintf (file, "/* prologue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n",
225 size);
227 /* Unless we're a leaf we need to save the return PC. */
229 if (! leaf_func_p)
231 OUT_AS1 (push, calll);
232 OUT_AS1 (push, callh);
233 prologue_size += 4;
236 /* We need to save the old FP and set the new FP pointing at the
237 stack location where the old one is saved. Note that because of
238 post-decrement addressing, the SP is off-by-one after the
239 push, so we harvest the SP address BEFORE we push the MSBs of
240 the FP. */
241 if (CHAIN_FRAMES)
243 OUT_AS1 (push, REG_FP+1); /* Save old LSBs. */
244 OUT_AS2 (mov, w, spl);
245 OUT_AS2 (mov, REG_FP+1, w); /* SPL -> FPL */
247 OUT_AS2 (mov, w, sph); /* Freeze SP MSBs */
248 OUT_AS1 (push, REG_FP); /* Save old MSBs */
249 OUT_AS2 (mov, REG_FP, w); /* SPH -> FPH */
250 prologue_size += 12;
253 for (reg = (CHAIN_FRAMES) ? (REG_FP - 1) : (REG_FP + 1);
254 reg > 0; --reg)
256 if (regs_ever_live[reg] && ! call_used_regs[reg])
258 fprintf (file, "\t" AS1 (push,%s) "\n", reg_names[reg]);
259 prologue_size += 2;
263 if (size)
265 operands[0] = GEN_INT (size);
267 switch (size & 0xff)
269 case 0:
270 break;
271 case 1:
272 OUT_AS1 (dec, spl);
273 prologue_size += 2;
274 break;
275 default:
276 OUT_AS2 (mov, w, %L0);
277 OUT_AS2 (sub, spl, w);
278 prologue_size += 4;
281 switch (size & 0xff00)
283 case 0:
284 break;
285 case 0x100:
286 OUT_AS1 (dec, sph);
287 prologue_size += 2;
288 break;
289 default:
290 if ((size & 0xff) != ((size >> 8) & 0xff))
291 OUT_AS2 (mov, w, %H0); /* Otherwise W has value we want. */
292 OUT_AS2 (sub, sph, w);
293 prologue_size += 4;
297 /* XXX - change this to use the carry-propagating subtract trick. */
298 if (flag_stack_check)
300 OUT_AS2 (mov, w, sph);
301 OUT_AS2 (cmp, w, #%%hi8data(_end));
302 OUT_AS1 (sc, ); /* C == 0 -> hi8(edata) < sph */
303 OUT_AS1 (page, 1f);
304 OUT_AS1 (jmp, 1f);
305 OUT_AS1 (sz, ); /* Z == 1 -> look at low byte */
306 OUT_AS1 (page,0f);
307 OUT_AS1 (jmp,0f); /* sp < edata, so raise stack fault */
308 OUT_AS2 (mov, w, spl);
309 OUT_AS2 (cmp, w, #%%lo8data(_end));
310 OUT_AS1 (sc,); /* C==1 -> lo8(edata) >= spl */
311 OUT_AS1 (page,1f);
312 OUT_AS1 (jmp,1f);
313 OUT_AS1 (0:,);
314 output_asm_insn ("push\t$ff", operands);
315 OUT_AS1 (system,);
316 OUT_AS1 (1:, );
317 prologue_size += 30;
321 /* Output function epilogue. */
322 void
323 function_epilogue (FILE *file, HOST_WIDE_INT size)
325 int leaf_func_p;
326 int reg,savelimit;
327 rtx operands[2]; /* Dummy used by OUT_ASn */
328 int args_locals_size = current_function_args_size;
329 int saved_regs_p = 0;
330 int need_ret = 1;
332 /* Use this opportunity to reset the reorg flags! */
333 ip2k_reorg_in_progress = 0;
334 ip2k_reorg_completed = 0;
335 ip2k_reorg_split_dimode = 0;
336 ip2k_reorg_split_simode = 0;
337 ip2k_reorg_split_himode = 0;
338 ip2k_reorg_split_qimode = 0;
339 ip2k_reorg_merge_qimode = 0;
341 if (ip2k_naked_function_p (current_function_decl))
343 fprintf (file, "/* epilogue: naked */\n");
344 return;
347 leaf_func_p = leaf_function_p ();
348 epilogue_size = 0;
349 fprintf (file, "/* epilogue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n",
350 size);
352 savelimit = (CHAIN_FRAMES) ? REG_FP : (REG_FP + 2);
353 for (reg = 0; reg < savelimit; reg++)
354 if (regs_ever_live[reg] && ! call_used_regs[reg])
356 saved_regs_p = 1;
357 break;
360 if (size)
362 if (leaf_func_p && !CHAIN_FRAMES && !saved_regs_p
363 && current_function_pops_args)
364 args_locals_size = current_function_args_size + size;
365 else
367 operands[0] = GEN_INT (size);
369 switch (size & 0xff)
371 default:
372 OUT_AS2 (mov, w, %L0);
373 OUT_AS2 (add, spl, w);
374 epilogue_size += 4;
375 /* fall-through */
376 case 0:
377 break;
378 case 1:
379 OUT_AS1 (inc, spl);
380 epilogue_size += 2;
383 switch (size & 0xff00)
385 default:
386 if ((size & 0xff) != ((size >> 8) & 0xff))
387 OUT_AS2 (mov, w, %H0);
388 OUT_AS2 (add, sph, w);
389 epilogue_size += 4;
390 /* fall-through */
391 case 0:
392 break;
393 case 0x100:
394 OUT_AS1 (inc, sph);
395 epilogue_size += 2;
400 for (reg = 0; reg < savelimit; reg++)
402 if (regs_ever_live[reg] && ! call_used_regs[reg])
404 fprintf (file, "\t" AS1 (pop,%s) "\n", reg_names[reg]);
405 prologue_size += 2;
409 if (CHAIN_FRAMES
410 && ! (current_function_pops_args
411 && current_function_args_size >= 2
412 && current_function_args_size < 0x100))
414 OUT_AS1 (pop, REG_FP);
415 OUT_AS1 (pop, REG_FP+1);
416 epilogue_size += 4;
419 if (! leaf_func_p)
421 if (current_function_pops_args
422 && current_function_args_size >= 2
423 && current_function_args_size < 0x100)
425 if (current_function_args_size == 2)
427 if (CHAIN_FRAMES)
429 OUT_AS1 (page, __fp_pop2_args_ret);
430 OUT_AS1 (jmp, __fp_pop2_args_ret);
432 else
434 OUT_AS1 (page, __pop2_args_ret);
435 OUT_AS1 (jmp, __pop2_args_ret);
437 epilogue_size += 4;
439 else
441 operands[0] = GEN_INT (current_function_args_size);
442 OUT_AS2 (mov, w, %L0);
443 if (CHAIN_FRAMES)
445 OUT_AS1 (page, __fp_pop_args_ret);
446 OUT_AS1 (jmp, __fp_pop_args_ret);
448 else
450 OUT_AS1 (page, __pop_args_ret);
451 OUT_AS1 (jmp, __pop_args_ret);
453 epilogue_size += 6;
455 need_ret = 0;
457 else
459 OUT_AS1 (pop, callh);
460 OUT_AS1 (pop, calll);
461 epilogue_size += 4;
464 else
466 if (current_function_pops_args
467 && args_locals_size >= 2
468 && args_locals_size < 0x100)
470 if (args_locals_size == 2)
472 if (CHAIN_FRAMES)
474 OUT_AS1 (page, __leaf_fp_pop2_args_ret);
475 OUT_AS1 (jmp, __leaf_fp_pop2_args_ret);
476 epilogue_size += 4;
477 need_ret = 0;
480 else
482 operands[0] = GEN_INT (args_locals_size);
483 if (CHAIN_FRAMES)
485 OUT_AS2 (mov, w, %L0);
486 OUT_AS1 (page, __leaf_fp_pop_args_ret);
487 OUT_AS1 (jmp, __leaf_fp_pop_args_ret);
488 epilogue_size += 6;
489 need_ret = 0;
495 if (current_function_pops_args && args_locals_size && need_ret)
497 operands[0] = GEN_INT (args_locals_size);
499 switch (args_locals_size & 0xff)
501 default:
502 OUT_AS2 (mov, w, %L0);
503 OUT_AS2 (add, spl, w);
504 epilogue_size += 4;
505 /* fall-through */
507 case 0:
508 break;
510 case 1:
511 OUT_AS1 (inc, spl);
512 epilogue_size += 2;
515 switch (args_locals_size & 0xff00)
517 default:
518 if ((args_locals_size & 0xff) != ((args_locals_size >> 8) & 0xff))
519 OUT_AS2 (mov, w, %H0);
520 OUT_AS2 (add, sph, w);
521 epilogue_size += 4;
522 /* fall-through */
524 case 0:
525 break;
527 case 0x100:
528 OUT_AS1 (inc, sph);
529 epilogue_size += 2;
533 if (need_ret)
535 OUT_AS1 (ret,);
536 epilogue_size += 2;
539 fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
542 /* Return the difference between the registers after the function
543 prologue.
545 Stack Frame grows down:
547 ARGUMENTS
548 <------ AP ($102:$103)
549 RETURN PC (unless leaf function)
550 SAVEDFP (if needed)
551 <------ FP [HARD_FRAME_POINTER] ($FD:$FE)
552 SAVED REGS
553 <------ VFP [$100:$101]
554 STACK ALLOCATION
555 <------ SP ($6:$7) */
557 ip2k_init_elim_offset (int from, int to)
559 int leaf_func_p = leaf_function_p ();
560 int no_saved_pc = leaf_func_p
561 || ip2k_naked_function_p (current_function_decl);
562 int offset;
563 int reg;
564 int reglimit;
566 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
567 return get_frame_size () + 1;
569 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
570 return (CHAIN_FRAMES ? 2 : 0) + (no_saved_pc ? 0 : 2);
572 /* Count all the registers we had to preserve. */
574 reglimit = CHAIN_FRAMES ? REG_FP : (REG_FP + 2);
575 for (offset = 0,reg = 0; reg < reglimit; ++reg)
577 if ((regs_ever_live[reg] && ! call_used_regs[reg]))
579 ++offset;
583 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
584 return -offset;
586 if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
587 /* Add in the stack-local variables. */
588 return offset + get_frame_size () + 1;
590 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
591 /* Add stack-locals plus saved FP and PC. */
592 return offset + get_frame_size () + 1
593 + (CHAIN_FRAMES ? 2 : 0) + (no_saved_pc ? 0 : 2);
595 abort (); /* Unanticipated elimination. */
598 /* Return nonzero if X (an RTX) is a legitimate memory address on the target
599 machine for a memory operand of mode MODE. */
602 legitimate_address_p (enum machine_mode mode, rtx x, int strict)
604 int off;
606 if (GET_CODE (x) == SUBREG)
607 x = SUBREG_REG (x);
609 switch (GET_CODE (x))
611 case REG:
612 /* IP allows indirection without offset - only okay if
613 we don't require access to multiple bytes. */
614 if (REGNO (x) == REG_IP)
615 return (GET_MODE_SIZE (mode) == 1) ? 'R' : 0;
617 /* We can indirect through DP or SP register. */
618 if (strict ? REG_OK_FOR_BASE_STRICT_P (x)
619 : REG_OK_FOR_BASE_NOSTRICT_P (x))
620 return 'S';
621 break;
623 case PLUS:
624 /* Offsets from DP or SP are legal in the range 0..127 */
626 rtx op1, op2;
628 op1 = XEXP (x, 0);
629 op2 = XEXP (x, 1);
631 if (REG_P (op2) && ! REG_P (op1))
633 rtx tmp = op1;
634 op1 = op2;
635 op2 = tmp;
638 /* Don't let anything but R+I through.. */
639 if (! REG_P (op1)
640 || REG_P (op2)
641 || GET_CODE (op2) != CONST_INT)
642 return 0;
644 switch (REGNO (op1))
646 case REG_DP: /* only 0..127 displacement */
647 case REG_SP:
648 off = 2 * GET_MODE_SIZE (mode);
649 if (! off)
650 off = 1;
652 if (INTVAL (op2) < 0 || INTVAL (op2) > (128 - off))
653 return 0; /* Positive must be small enough that after
654 splitting all pieces are addressed. */
655 return 'S'; /* Safe displacement. */
657 case REG_IP:
658 if (GET_MODE_SIZE (mode) <= 1 && INTVAL (op2) == 0)
659 return (GET_MODE_SIZE (mode) == 1) ? 'R' : 0;
660 return 0;
662 case REG_AP:
663 case REG_FP:
664 case REG_VFP:
665 default:
666 if (strict || ! REG_OK_FOR_BASE_NOSTRICT_P (op1))
667 return 0; /* Allow until reload. */
669 return 'S';
672 break;
674 case CONST:
675 case SYMBOL_REF:
676 /* We always allow references to things in code space. */
677 return is_regfile_address (x) ? 0 : 'C';
679 case LABEL_REF:
680 return 'L';
682 default:
683 return 0;
686 return 0;
689 /* Is ADDR mode dependent? */
691 ip2k_mode_dependent_address (rtx addr)
693 switch (GET_CODE (addr))
695 case POST_INC:
696 case POST_DEC:
697 case PRE_INC:
698 case PRE_DEC:
699 return 1;
701 case REG:
702 return (REGNO (addr) == REG_IP); /* Can't do IP displaced addresses. */
704 default:
705 return 0; /* Assume no dependency. */
709 /* Attempts to replace X with a valid
710 memory address for an operand of mode MODE. */
713 legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
714 enum machine_mode mode ATTRIBUTE_UNUSED, rtx scratch)
716 rtx reg;
718 /* You might think that we could split up a symbolic address by
719 adding the HIGH 8 bits and doing a displacement off the dp. But
720 because we only have 7 bits of offset, that doesn't actually
721 help. So only constant displacements are likely to obtain an
722 advantage. */
724 if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0))
725 && GET_CODE (XEXP (x, 1)) == CONST_INT
726 && ! CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'K'))
728 int offset = INTVAL (XEXP (x, 1));
730 reg = scratch ? scratch : gen_reg_rtx (Pmode);
732 emit_insn (gen_rtx_SET (VOIDmode, reg,
733 gen_rtx_PLUS (Pmode, XEXP (x, 0),
734 GEN_INT (offset & 0xffc0))));
735 x = gen_rtx_PLUS (Pmode, reg, GEN_INT (offset & 0x3f));
738 return x; /* We don't have any other tricks. */
741 /* Determine if X is a 'data' address or a code address. All static
742 data and stack variables reside in data memory. Only code is believed
743 to be in PRAM or FLASH. */
745 is_regfile_address (rtx x)
747 while (1)
748 switch (GET_CODE (x))
750 case SYMBOL_REF:
751 return ! SYMBOL_REF_FUNCTION_P (x); /* Declared as function. */
752 case CONST:
753 case PLUS:
754 x = XEXP (x, 0);
755 break;
756 case CONST_INT:
757 case REG:
758 case SUBREG:
759 return 1;
760 case LABEL_REF:
761 return 0;
762 default:
763 return 0;
766 return 0;
769 /* Output ADDR to FILE as address. */
771 void
772 print_operand_address (FILE *file, rtx addr)
774 switch (GET_CODE (addr))
776 case SUBREG:
777 addr = alter_subreg (&addr);
778 /* fall-through */
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;
790 case PRE_DEC:
791 case POST_INC:
792 abort ();
793 break;
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;
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;
812 case PLUS: /* Ought to be stack or dp references. */
813 if (XEXP (addr, 1) == const0_rtx
814 && GET_CODE (XEXP (addr, 0)) == PLUS)
816 print_operand_address (file, XEXP (addr, 0));
817 return;
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;
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;
834 default:
835 output_addr_const (file, addr);
840 /* Output X as assembler operand to file FILE. */
842 void
843 print_operand (FILE *file, rtx x, int code)
845 int abcd = 0;
846 unsigned long value;
848 switch (code)
850 case '<': /* Push */
851 ip2k_stack_delta++;
852 return;
854 case '>': /* Pop */
855 ip2k_stack_delta--;
856 return;
858 case 'A':
859 case 'B':
860 case 'C':
861 case 'D':
862 abcd = code - 'A';
863 break;
865 case 'H':
866 abcd = 0;
867 break;
869 case 'L':
870 abcd = 1;
871 break;
873 case 'S':
874 case 'T':
875 case 'U':
876 case 'V':
877 case 'W':
878 case 'X':
879 case 'Y':
880 case 'Z':
881 abcd = code - 'S';
883 default:
884 break;
887 if (ip2k_short_operand (x, GET_MODE (x))
888 && ip2k_address_uses_reg_p (x, REG_SP))
889 /* An SP-relative address needs to account for interior stack
890 pushes that reload didn't know about when it calculated the
891 stack offset. */
892 abcd += ip2k_stack_delta;
894 switch (GET_CODE (x))
896 case SUBREG:
897 x = alter_subreg (&x);
898 /* fall-through */
900 case REG:
901 fprintf (file, reg_names[true_regnum (x) + abcd]);
902 break;
904 case CONST_INT:
905 switch (code)
907 case 'x':
908 fprintf (file, "$%x", (int)(INTVAL (x) & 0xffff));
909 break;
911 case 'b':
912 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); /* bit selector */
913 break;
915 case 'e': /* "1 << n" - e.g. "exp" */
916 fprintf (file, "#%d", 1 << INTVAL (x));
917 break;
919 case 'A':
920 case 'B':
921 case 'C':
922 case 'D':
923 value = INTVAL (x);
924 value >>= 8 * (3 - abcd);
925 value &= 0xff;
927 fprintf (file, "#%ld", value);
928 break;
930 case 'H':
931 fprintf (file, "#%d", (int)((INTVAL (x) >> 8) & 0xff));
932 break;
934 case 'L':
935 fprintf (file, "#%d", (int)(INTVAL (x) & 0xff));
936 break;
938 case 'S':
939 case 'T':
940 case 'U':
941 case 'V':
942 case 'W':
943 case 'X':
944 case 'Y':
945 case 'Z':
946 value = ((unsigned long long)INTVAL (x)) >> (8 * (7 - abcd)) & 0xff;
947 fprintf (file, "#%ld", value);
948 break;
950 default:
951 fprintf (file, "#" HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
953 break;
955 case SYMBOL_REF:
956 case LABEL_REF:
957 case CODE_LABEL:
958 case CONST:
959 switch (code)
961 case 'A':
962 case 'B':
963 case 'C':
964 case 'D':
965 case 'S':
966 case 'T':
967 case 'U':
968 case 'V':
969 case 'W':
970 case 'X':
971 case 'Y':
972 case 'Z':
973 abort (); /* Probably an error. */
974 break;
976 case 'H':
977 fprintf (file, "#%s(",
978 is_regfile_address (x) ? "%hi8data"
979 : "%hi8insn");
980 print_operand_address (file, x);
981 fputc (')', file);
982 break;
984 case 'L':
985 fprintf (file, "#%s(",
986 is_regfile_address (x) ? "%lo8data"
987 : "%lo8insn");
988 print_operand_address (file, x);
989 fputc (')', file);
990 break;
992 default:
993 print_operand_address (file, x);
995 break;
997 case MEM:
999 rtx addr = XEXP (x, 0);
1001 if (GET_CODE (addr) == SUBREG)
1002 addr = alter_subreg (&x);
1004 if (CONSTANT_P (addr) && abcd)
1006 fputc ('(', file);
1007 print_operand_address (file, addr);
1008 fprintf (file, ")+%d", abcd);
1010 else if (abcd)
1012 switch (GET_CODE (addr))
1014 case PLUS:
1015 abcd += INTVAL (XEXP (addr, 1));
1017 /* Worry about (plus (plus (reg DP) (const_int 10))
1018 (const_int 0)) */
1019 if (GET_CODE (XEXP (addr, 0)) == PLUS)
1021 addr = XEXP (addr, 0);
1022 abcd += INTVAL (XEXP (addr, 1));
1025 fprintf (file, "%d", abcd);
1026 print_operand_address (file, XEXP (addr, 0));
1027 break;
1029 case REG:
1030 default:
1031 fprintf (file, "%d", abcd);
1032 print_operand_address (file, addr);
1035 else if (GET_CODE (addr) == REG
1036 && (REGNO (addr) == REG_DP || REGNO (addr) == REG_SP))
1038 fprintf (file, "0");
1039 print_operand_address (file, addr);
1041 else
1042 print_operand_address (file, addr);
1044 break;
1046 case CONST_DOUBLE:
1047 /* Is this an integer or a floating point value? */
1048 if (GET_MODE (x) == VOIDmode)
1050 switch (code)
1052 case 'S':
1053 case 'T':
1054 case 'U':
1055 case 'V':
1056 value = CONST_DOUBLE_HIGH (x);
1057 value >>= 8 * (3 - abcd);
1058 value &= 0xff;
1060 fprintf (file, "#%ld", value);
1061 break;
1063 case 'W':
1064 case 'X':
1065 case 'Y':
1066 case 'Z':
1067 value = CONST_DOUBLE_LOW (x);
1068 value >>= 8 * (7 - abcd);
1069 value &= 0xff;
1071 fprintf (file, "#%ld", value);
1072 break;
1076 else
1078 REAL_VALUE_TYPE rv;
1080 REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1081 REAL_VALUE_TO_TARGET_SINGLE (rv, value);
1082 fprintf (file, "0x%lx", value);
1084 break;
1086 default:
1087 fatal_insn ("bad operand", x);
1091 /* Remember the operands for the compare. */
1092 const char *
1093 ip2k_set_compare (rtx x, rtx y)
1095 ip2k_compare_operands[0] = x;
1096 ip2k_compare_operands[1] = y;
1097 return "";
1100 /* Emit the code for sCOND instructions. */
1101 const char *
1102 ip2k_gen_sCOND (rtx insn ATTRIBUTE_UNUSED, enum rtx_code code, rtx dest)
1104 #define operands ip2k_compare_operands
1105 enum machine_mode mode;
1107 operands[2] = dest;
1109 mode = GET_MODE (operands[0]);
1110 if ((mode != QImode) && (mode != HImode)
1111 && (mode != SImode) && (mode != DImode))
1112 mode = GET_MODE (operands[1]);
1114 /* We have a fast path for a specific type of QImode compare. We ought
1115 to extend this for larger cases too but that wins less frequently and
1116 introduces a lot of complexity. */
1117 if (mode == QImode
1118 && !rtx_equal_p (operands[0], operands[2])
1119 && !rtx_equal_p (operands[1], operands[2])
1120 && (! REG_P (operands[2])
1121 || (ip2k_xexp_not_uses_reg_p (operands[0], REGNO (operands[2]), 1)
1122 && ip2k_xexp_not_uses_reg_p (operands[1],
1123 REGNO (operands[2]), 1))))
1125 OUT_AS1 (clr, %2);
1126 if (immediate_operand (operands[1], QImode)
1127 && ((INTVAL (operands[1]) & 0xff) == 0xff))
1129 if (code == EQ)
1130 OUT_AS2 (incsnz, w, %0);
1131 else
1132 OUT_AS2 (incsz, w, %0);
1134 else if (immediate_operand (operands[1], QImode)
1135 && ((INTVAL (operands[1]) & 0xff) == 0x01))
1137 if (code == EQ)
1138 OUT_AS2 (decsnz, w, %0);
1139 else
1140 OUT_AS2 (decsz, w, %0);
1142 else if (ip2k_compare_operands[1] == const0_rtx)
1144 OUT_AS2 (mov, w, %0);
1145 if (code == EQ)
1146 OUT_AS1 (snz,);
1147 else
1148 OUT_AS1 (sz,);
1150 else
1152 OUT_AS2 (mov, w, %0);
1153 if (code == EQ)
1154 OUT_AS2 (csne, w, %1);
1155 else
1156 OUT_AS2 (cse, w, %1);
1158 OUT_AS1 (inc, %2);
1160 else
1162 if (ip2k_compare_operands[1] == const0_rtx)
1164 switch (mode)
1166 case QImode:
1167 OUT_AS2 (mov, w, %0);
1168 break;
1170 case HImode:
1171 OUT_AS2 (mov, w, %H0);
1172 OUT_AS2 (or, w, %L0);
1173 break;
1175 case SImode:
1176 OUT_AS2 (mov, w, %A0);
1177 OUT_AS2 (or, w, %B0);
1178 OUT_AS2 (or, w, %C0);
1179 OUT_AS2 (or, w, %D0);
1180 break;
1182 case DImode:
1183 OUT_AS2 (mov, w, %S0);
1184 OUT_AS2 (or, w, %T0);
1185 OUT_AS2 (or, w, %U0);
1186 OUT_AS2 (or, w, %V0);
1187 OUT_AS2 (or, w, %W0);
1188 OUT_AS2 (or, w, %X0);
1189 OUT_AS2 (or, w, %Y0);
1190 OUT_AS2 (or, w, %Z0);
1191 break;
1193 default:
1194 abort ();
1197 else
1199 switch (mode)
1201 case QImode:
1202 OUT_AS2 (mov, w, %1);
1203 OUT_AS2 (cmp, w, %0);
1204 break;
1206 case HImode:
1207 OUT_AS2 (mov, w, %H1);
1208 OUT_AS2 (cmp, w, %H0);
1209 OUT_AS1 (sz,);
1210 OUT_AS1 (page, 2f);
1211 OUT_AS1 (jmp, 2f);
1212 OUT_AS2 (mov, w, %L1);
1213 OUT_AS2 (cmp, w, %L0);
1214 OUT_AS1 (2:,);
1215 break;
1217 case SImode:
1218 if (code == EQ)
1220 OUT_AS2 (mov, w, #1);
1221 OUT_AS2 (mov, mulh, w);
1223 else
1224 OUT_AS1 (clr, mulh);
1225 OUT_AS2 (mov, w, %A1);
1226 OUT_AS2 (cse, w, %A0);
1227 OUT_AS1 (page, 2f);
1228 OUT_AS1 (jmp, 2f);
1229 OUT_AS2 (mov, w, %B1);
1230 OUT_AS2 (cse, w, %B0);
1231 OUT_AS1 (page, 2f);
1232 OUT_AS1 (jmp, 2f);
1233 OUT_AS2 (mov, w, %C1);
1234 OUT_AS2 (cse, w, %C0);
1235 OUT_AS1 (page, 2f);
1236 OUT_AS1 (jmp, 2f);
1237 OUT_AS2 (mov, w, %D1);
1238 OUT_AS2 (cse, w, %D0);
1239 OUT_AS1 (2:,);
1240 if (code == EQ)
1241 OUT_AS1 (dec, mulh);
1242 else
1243 OUT_AS1 (inc, mulh);
1244 OUT_AS2 (mov, w, mulh);
1245 OUT_AS2 (mov, %2, w);
1246 return "";
1248 case DImode:
1249 if (code == EQ)
1251 OUT_AS2 (mov, w, #1);
1252 OUT_AS2 (mov, mulh, w);
1254 else
1255 OUT_AS1 (clr, mulh);
1256 OUT_AS2 (mov, w, %S1);
1257 OUT_AS2 (cse, w, %S0);
1258 OUT_AS1 (page, 2f);
1259 OUT_AS1 (jmp, 2f);
1260 OUT_AS2 (mov, w, %T1);
1261 OUT_AS2 (cse, w, %T0);
1262 OUT_AS1 (page, 2f);
1263 OUT_AS1 (jmp, 2f);
1264 OUT_AS2 (mov, w, %U1);
1265 OUT_AS2 (cse, w, %U0);
1266 OUT_AS1 (page, 2f);
1267 OUT_AS1 (jmp, 2f);
1268 OUT_AS2 (mov, w, %V1);
1269 OUT_AS2 (cse, w, %V0);
1270 OUT_AS1 (page, 2f);
1271 OUT_AS1 (jmp, 2f);
1272 OUT_AS2 (mov, w, %W1);
1273 OUT_AS2 (cse, w, %W0);
1274 OUT_AS1 (page, 2f);
1275 OUT_AS1 (jmp, 2f);
1276 OUT_AS2 (mov, w, %X1);
1277 OUT_AS2 (cse, w, %X0);
1278 OUT_AS1 (page, 2f);
1279 OUT_AS1 (jmp, 2f);
1280 OUT_AS2 (mov, w, %Y1);
1281 OUT_AS2 (cse, w, %Y0);
1282 OUT_AS1 (page, 2f);
1283 OUT_AS1 (jmp, 2f);
1284 OUT_AS2 (mov, w, %Z1);
1285 OUT_AS2 (cse, w, %Z0);
1286 OUT_AS1 (2:,);
1287 if (code == EQ)
1288 OUT_AS1 (dec, mulh);
1289 else
1290 OUT_AS1 (inc, mulh);
1291 OUT_AS2 (mov, w, mulh);
1292 OUT_AS2 (mov, %2, w);
1293 return "";
1295 default:
1296 abort ();
1299 OUT_AS2 (mov, w, #0);
1300 if (code == EQ)
1301 OUT_AS1 (snz,);
1302 else
1303 OUT_AS1 (sz,);
1304 OUT_AS1 (inc, wreg);
1305 OUT_AS2 (mov, %2, w);
1308 return "";
1309 #undef operands
1312 const char *
1313 ip2k_gen_signed_comp_branch (rtx insn, enum rtx_code code, rtx label)
1315 #define operands ip2k_compare_operands
1316 enum machine_mode mode;
1317 int can_use_skip = 0;
1318 rtx ninsn;
1320 operands[2] = label;
1322 mode = GET_MODE (operands[0]);
1323 if ((mode != QImode) && (mode != HImode)
1324 && (mode != SImode) && (mode != DImode))
1325 mode = GET_MODE (operands[1]);
1327 /* Look for situations where we can just skip the next instruction instead
1328 of skipping and then branching! */
1329 ninsn = next_real_insn (insn);
1330 if (ninsn
1331 && (recog_memoized (ninsn) >= 0)
1332 && get_attr_skip (ninsn) == SKIP_YES)
1334 rtx skip_tgt = next_nonnote_insn (next_real_insn (insn));
1336 /* The first situation is where the target of the jump is one insn
1337 after the jump insn and the insn being jumped is only one machine
1338 opcode long. */
1339 if (label == skip_tgt)
1340 can_use_skip = 1;
1341 else
1343 /* If our skip target is in fact a code label then we ignore the
1344 label and move onto the next useful instruction. Nothing we do
1345 here has any effect on the use of skipping instructions. */
1346 if (GET_CODE (skip_tgt) == CODE_LABEL)
1347 skip_tgt = next_nonnote_insn (skip_tgt);
1349 /* The second situation is where we have something of the form:
1351 test_condition
1352 skip_conditional
1353 page/jump label
1355 optional_label (this may or may not exist):
1356 skippable_insn
1357 page/jump label
1359 In this case we can eliminate the first "page/jump label". */
1360 if (GET_CODE (skip_tgt) == JUMP_INSN)
1362 rtx set = single_set (skip_tgt);
1363 if (GET_CODE (XEXP (set, 0)) == PC
1364 && GET_CODE (XEXP (set, 1)) == LABEL_REF
1365 && label == JUMP_LABEL (skip_tgt))
1366 can_use_skip = 2;
1371 /* gcc is a little braindead and does some rather stateful things while
1372 inspecting attributes - we have to put this state back to what it's
1373 supposed to be. */
1374 extract_constrain_insn_cached (insn);
1376 if (ip2k_compare_operands[1] == const0_rtx) /* These are easier. */
1378 switch (code)
1380 case LT:
1381 if (can_use_skip)
1383 OUT_AS2 (sb, %0, 7);
1385 else
1387 OUT_AS2 (snb, %0, 7);
1388 OUT_AS1 (page, %2);
1389 OUT_AS1 (jmp, %2);
1391 break;
1393 case GT:
1394 switch (mode)
1396 case DImode:
1397 OUT_AS2 (rl, w, %S0);
1398 OUT_AS2 (mov, w, %S0);
1399 OUT_AS2 (or, w, %T0);
1400 OUT_AS2 (or, w, %U0);
1401 OUT_AS2 (or, w, %V0);
1402 OUT_AS2 (or, w, %W0);
1403 OUT_AS2 (or, w, %X0);
1404 OUT_AS2 (or, w, %Y0);
1405 OUT_AS2 (or, w, %Z0);
1406 OUT_AS1 (snz, );
1407 OUT_AS2 (setb, status, 0);
1408 OUT_AS2 (sb, status, 0);
1409 OUT_AS1 (page, %2);
1410 OUT_AS1 (jmp, %2);
1411 break;
1413 case SImode:
1414 OUT_AS2 (rl, w, %A0);
1415 OUT_AS2 (mov, w, %A0);
1416 OUT_AS2 (or, w, %B0);
1417 OUT_AS2 (or, w, %C0);
1418 OUT_AS2 (or, w, %D0);
1419 OUT_AS1 (snz, );
1420 OUT_AS2 (setb, status, 0);
1421 OUT_AS2 (sb, status, 0);
1422 OUT_AS1 (page, %2);
1423 OUT_AS1 (jmp, %2);
1424 break;
1426 case HImode:
1427 OUT_AS2 (rl, w, %H0);
1428 OUT_AS2 (mov, w, %H0);
1429 OUT_AS2 (or, w, %L0);
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;
1437 case QImode:
1438 OUT_AS2 (mov, w, %0); /* Will just do "sb w, 7". */
1439 OUT_AS1 (snz, );
1440 OUT_AS2 (setb, wreg, 7);
1441 OUT_AS2 (sb, wreg, 7);
1442 OUT_AS1 (page, %2);
1443 OUT_AS1 (jmp, %2);
1444 break;
1446 default:
1447 abort ();
1449 break;
1451 case LE:
1452 switch (mode)
1454 case DImode:
1455 OUT_AS2 (mov, w, %S0);
1456 OUT_AS2 (or, w, %T0);
1457 OUT_AS2 (or, w, %U0);
1458 OUT_AS2 (or, w, %V0);
1459 OUT_AS2 (or, w, %W0);
1460 OUT_AS2 (or, w, %X0);
1461 OUT_AS2 (or, w, %Y0);
1462 OUT_AS2 (or, w, %Z0); /* Z is correct. */
1463 OUT_AS1 (sz, );
1464 OUT_AS2 (snb, %S0, 7);
1465 OUT_AS1 (page, %2);
1466 OUT_AS1 (jmp, %2);
1467 break;
1469 case SImode:
1470 OUT_AS2 (mov, w, %A0);
1471 OUT_AS2 (or, w, %B0);
1472 OUT_AS2 (or, w, %C0);
1473 OUT_AS2 (or, w, %D0); /* Z is correct. */
1474 OUT_AS1 (sz, );
1475 OUT_AS2 (snb, %A0, 7);
1476 OUT_AS1 (page, %2);
1477 OUT_AS1 (jmp, %2);
1478 break;
1480 case HImode:
1481 OUT_AS2 (mov, w, %H0);
1482 OUT_AS2 (or, w, %L0);
1483 OUT_AS1 (sz, );
1484 OUT_AS2 (snb, %H0, 7);
1485 OUT_AS1 (page, %2);
1486 OUT_AS1 (jmp, %2);
1487 break;
1489 case QImode:
1490 OUT_AS2 (mov, w, %0); /* Will just do "sb w, 7". */
1491 OUT_AS1 (sz, );
1492 OUT_AS2 (snb, wreg, 7);
1493 OUT_AS1 (page, %2);
1494 OUT_AS1 (jmp, %2);
1495 break;
1497 default:
1498 abort ();
1500 break;
1502 case GE:
1503 if (can_use_skip)
1505 OUT_AS2 (snb, %0, 7);
1507 else
1509 OUT_AS2 (sb, %0, 7);
1510 OUT_AS1 (page, %2);
1511 OUT_AS1 (jmp, %2);
1513 break;
1515 default:
1516 abort ();
1518 return "";
1521 /* signed compares are out of line because we can't get
1522 the hardware to compute the overflow for us. */
1524 switch (mode)
1526 case QImode:
1527 OUT_AS1 (push, %1%<);
1528 OUT_AS1 (push, %0%>);
1529 OUT_AS1 (page, __cmpqi2);
1530 OUT_AS1 (call, __cmpqi2);
1531 break;
1533 case HImode:
1534 OUT_AS1 (push, %L1%<);
1535 OUT_AS1 (push, %H1%<);
1536 OUT_AS1 (push, %L0%<);
1537 OUT_AS1 (push, %H0%>%>%>);
1538 OUT_AS1 (page, __cmphi2);
1539 OUT_AS1 (call, __cmphi2);
1540 break;
1542 case SImode:
1543 OUT_AS1 (push, %D1%<);
1544 OUT_AS1 (push, %C1%<);
1545 OUT_AS1 (push, %B1%<);
1546 OUT_AS1 (push, %A1%<);
1547 OUT_AS1 (push, %D0%<);
1548 OUT_AS1 (push, %C0%<);
1549 OUT_AS1 (push, %B0%<);
1550 OUT_AS1 (push, %A0%>%>%>%>%>%>%>);
1551 OUT_AS1 (page, __cmpsi2);
1552 OUT_AS1 (call, __cmpsi2);
1553 break;
1555 case DImode:
1556 if (GET_CODE (operands[0]) == MEM
1557 && true_regnum (XEXP (operands[0], 0)) == REG_DP)
1559 OUT_AS1 (push, %Z1%<);
1560 OUT_AS1 (push, %Y1%<);
1561 OUT_AS1 (push, %X1%<);
1562 OUT_AS1 (push, %W1%<);
1563 OUT_AS1 (push, %V1%<);
1564 OUT_AS1 (push, %U1%<);
1565 OUT_AS1 (push, %T1%<);
1566 OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
1567 OUT_AS1 (page, __cmpdi2_dp);
1568 OUT_AS1 (call, __cmpdi2_dp);
1570 else
1572 OUT_AS1 (push, %Z1%<);
1573 OUT_AS1 (push, %Y1%<);
1574 OUT_AS1 (push, %X1%<);
1575 OUT_AS1 (push, %W1%<);
1576 OUT_AS1 (push, %V1%<);
1577 OUT_AS1 (push, %U1%<);
1578 OUT_AS1 (push, %T1%<);
1579 OUT_AS1 (push, %S1%<);
1580 OUT_AS1 (push, %Z0%<);
1581 OUT_AS1 (push, %Y0%<);
1582 OUT_AS1 (push, %X0%<);
1583 OUT_AS1 (push, %W0%<);
1584 OUT_AS1 (push, %V0%<);
1585 OUT_AS1 (push, %U0%<);
1586 OUT_AS1 (push, %T0%<);
1587 OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
1588 OUT_AS1 (page, __cmpdi2);
1589 OUT_AS1 (call, __cmpdi2);
1591 break;
1593 default:
1594 abort ();
1597 switch (code)
1599 case LT:
1600 if (can_use_skip)
1602 OUT_AS2 (cse, w, #0);
1604 else
1606 OUT_AS2 (csne, w, #0);
1607 OUT_AS1 (page, %2);
1608 OUT_AS1 (jmp, %2);
1610 break;
1612 case GT:
1613 if (can_use_skip)
1615 OUT_AS2 (cse, w, #2);
1617 else
1619 OUT_AS2 (csne, w, #2);
1620 OUT_AS1 (page, %2);
1621 OUT_AS1 (jmp, %2);
1623 break;
1625 case LE:
1626 if (can_use_skip)
1628 OUT_AS2 (snb, wreg, 1);
1630 else
1632 OUT_AS2 (sb, wreg, 1);
1633 OUT_AS1 (page, %2);
1634 OUT_AS1 (jmp, %2);
1636 break;
1638 case GE:
1639 if (can_use_skip)
1641 OUT_AS2 (csne, w, #0);
1643 else
1645 OUT_AS2 (cse, w, #0);
1646 OUT_AS1 (page, %2);
1647 OUT_AS1 (jmp, %2);
1649 break;
1651 default:
1652 abort ();
1654 return "";
1655 #undef operands
1658 const char *
1659 ip2k_gen_unsigned_comp_branch (rtx insn, enum rtx_code code, rtx label)
1661 #define operands ip2k_compare_operands
1662 enum machine_mode mode;
1663 int imm_sub = 0;
1664 int imm_cmp = 0;
1665 int can_use_skip = 0;
1666 rtx ninsn;
1667 HOST_WIDE_INT const_low;
1668 HOST_WIDE_INT const_high;
1670 operands[2] = label;
1672 mode = GET_MODE (operands[0]);
1673 if ((mode != QImode) && (mode != HImode) && (mode != SImode)
1674 && (mode != DImode))
1676 mode = GET_MODE (operands[1]);
1679 /* Look for situations where we can just skip the next instruction instead
1680 of skipping and then branching! */
1681 ninsn = next_real_insn (insn);
1682 if (ninsn
1683 && (recog_memoized (ninsn) >= 0)
1684 && get_attr_skip (ninsn) == SKIP_YES)
1686 rtx skip_tgt = next_nonnote_insn (next_real_insn (insn));
1688 /* The first situation is where the target of the jump is one insn
1689 after the jump insn and the insn being jumped is only one machine
1690 opcode long. */
1691 if (label == skip_tgt)
1692 can_use_skip = 1;
1693 else
1695 /* If our skip target is in fact a code label then we ignore the
1696 label and move onto the next useful instruction. Nothing we do
1697 here has any effect on the use of skipping instructions. */
1698 if (GET_CODE (skip_tgt) == CODE_LABEL)
1699 skip_tgt = next_nonnote_insn (skip_tgt);
1701 /* The second situation is where we have something of the form:
1703 test_condition
1704 skip_conditional
1705 page/jump label
1707 optional_label (this may or may not exist):
1708 skippable_insn
1709 page/jump label
1711 In this case we can eliminate the first "page/jump label". */
1712 if (GET_CODE (skip_tgt) == JUMP_INSN)
1714 rtx set = single_set (skip_tgt);
1715 if (GET_CODE (XEXP (set, 0)) == PC
1716 && GET_CODE (XEXP (set, 1)) == LABEL_REF
1717 && label == JUMP_LABEL (skip_tgt))
1718 can_use_skip = 2;
1723 /* gcc is a little braindead and does some rather stateful things while
1724 inspecting attributes - we have to put this state back to what it's
1725 supposed to be. */
1726 extract_constrain_insn_cached (insn);
1728 if (ip2k_compare_operands[1] == const0_rtx)
1730 switch (code)
1732 case LEU:
1733 code = EQ; /* Nothing is LTU 0. */
1734 goto zero;
1736 case GTU:
1737 code = NE; /* Anything nonzero is GTU. */
1738 /* fall-through */
1740 case EQ:
1741 case NE: /* Test all the bits, result in
1742 Z AND WREG. */
1743 zero:
1744 switch (mode)
1746 case DImode:
1747 OUT_AS2 (mov, w, %S0);
1748 OUT_AS2 (or, w, %T0);
1749 OUT_AS2 (or, w, %U0);
1750 OUT_AS2 (or, w, %V0);
1751 OUT_AS2 (or, w, %W0);
1752 OUT_AS2 (or, w, %X0);
1753 OUT_AS2 (or, w, %Y0);
1754 OUT_AS2 (or, w, %Z0);
1755 break;
1757 case SImode:
1758 OUT_AS2 (mov, w, %A0);
1759 OUT_AS2 (or, w, %B0);
1760 OUT_AS2 (or, w, %C0);
1761 OUT_AS2 (or, w, %D0);
1762 break;
1764 case HImode:
1765 OUT_AS2 (mov, w, %H0);
1766 OUT_AS2 (or, w, %L0);
1767 break;
1769 case QImode:
1770 OUT_AS2 (mov, w, %0);
1771 break;
1773 default:
1774 abort ();
1777 if (can_use_skip)
1779 if (code == EQ)
1780 OUT_AS1 (sz, );
1781 else
1782 OUT_AS1 (snz, );
1784 else
1786 if (code == EQ)
1787 OUT_AS1 (snz,);
1788 else
1789 OUT_AS1 (sz,);
1790 OUT_AS1 (page, %2);
1791 OUT_AS1 (jmp, %2);
1793 break;
1795 case GEU:
1796 /* Always succeed. */
1797 OUT_AS1 (page, %2);
1798 OUT_AS1 (jmp, %2);
1799 break;
1801 case LTU:
1802 /* Always fail. */
1803 break;
1805 default:
1806 abort ();
1808 return "";
1811 /* Look at whether we have a constant as one of our operands. If we do
1812 and it's in the position that we use to subtract from during our
1813 normal optimized comparison concept then we have to shuffle things
1814 around! */
1815 if (mode != QImode)
1817 if ((immediate_operand (operands[1], GET_MODE (operands[1]))
1818 && ((code == LEU) || (code == GTU)))
1819 || (immediate_operand (operands[0], GET_MODE (operands[0]))
1820 && ((code == LTU) || (code == GEU))))
1822 imm_sub = 1;
1826 /* Same as above - look if we have a constant that we can compare
1827 for equality or non-equality. If we know this then we can look
1828 for common value eliminations. Note that we want to ensure that
1829 any immediate value is operand 1 to simplify the code later! */
1830 if ((code == EQ) || (code == NE))
1832 imm_cmp = immediate_operand (operands[1], GET_MODE (operands[1]));
1833 if (! imm_cmp)
1835 imm_cmp = immediate_operand (operands[0], GET_MODE (operands[0]));
1836 if (imm_cmp)
1838 rtx tmp = operands[1];
1839 operands[1] = operands[0];
1840 operands[0] = tmp;
1845 switch (mode)
1847 case QImode:
1848 switch (code)
1850 case EQ:
1851 if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff))
1852 OUT_AS2 (incsnz, w, %0);
1853 else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01))
1854 OUT_AS2 (decsnz, w, %0);
1855 else
1857 OUT_AS2 (mov, w, %1);
1858 OUT_AS2 (csne, w, %0);
1860 OUT_AS1 (page, %2);
1861 OUT_AS1 (jmp, %2);
1862 break;
1864 case NE:
1865 if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0xff))
1866 OUT_AS2 (incsz, w, %0);
1867 else if (imm_cmp && ((INTVAL (operands[1]) & 0xff) == 0x01))
1868 OUT_AS2 (decsz, w, %0);
1869 else
1871 OUT_AS2 (mov, w, %1);
1872 OUT_AS2 (cse, w, %0);
1874 OUT_AS1 (page, %2);
1875 OUT_AS1 (jmp, %2);
1876 break;
1878 case GTU:
1879 OUT_AS2 (mov, w, %0);
1880 OUT_AS2 (cmp, w, %1);
1881 OUT_AS1 (sc,);
1882 OUT_AS1 (page, %2);
1883 OUT_AS1 (jmp, %2);
1884 break;
1886 case GEU:
1887 OUT_AS2 (mov, w, %1);
1888 OUT_AS2 (cmp, w, %0);
1889 OUT_AS1 (snc,);
1890 OUT_AS1 (page, %2);
1891 OUT_AS1 (jmp, %2);
1892 break;
1894 case LTU:
1895 OUT_AS2 (mov, w, %1);
1896 OUT_AS2 (cmp, w, %0);
1897 OUT_AS1 (sc,);
1898 OUT_AS1 (page, %2);
1899 OUT_AS1 (jmp, %2);
1900 break;
1902 case LEU:
1903 OUT_AS2 (mov, w, %0);
1904 OUT_AS2 (cmp, w, %1);
1905 OUT_AS1 (snc,);
1906 OUT_AS1 (page, %2);
1907 OUT_AS1 (jmp, %2);
1908 break;
1910 default:
1911 abort ();
1913 break;
1915 case HImode:
1916 switch (code)
1918 case EQ:
1920 unsigned char h = 0, l = 1;
1922 if (imm_cmp)
1924 h = (INTVAL (operands[1]) >> 8) & 0xff;
1925 l = INTVAL (operands[1]) & 0xff;
1927 if ((h == 0xff) && (l == 0xff))
1929 /* We should be able to do the following, but the
1930 IP2k simulator doesn't like it and we get a load
1931 of failures in gcc-c-torture. */
1932 OUT_AS2 (incsnz, w, %L0);
1933 OUT_AS2 (incsz, w, %H0);
1934 /* OUT_AS1 (skip,); Should have this */
1935 OUT_AS1 (page, 1f);/* Shouldn't need this! */
1936 OUT_AS1 (jmp, 1f); /* Shouldn't need this either. */
1937 OUT_AS1 (page, %2);
1938 OUT_AS1 (jmp, %2);
1939 OUT_AS1 (1:,);
1940 break;
1942 else if (h == 0)
1944 if (l == 1)
1945 OUT_AS2 (dec, w, %L0);
1946 else
1948 OUT_AS2 (mov, w, %L0);
1949 OUT_AS2 (sub, w, %L1);
1951 OUT_AS2 (or, w, %H0);
1952 OUT_AS1 (snz,);
1953 OUT_AS1 (page, %2);
1954 OUT_AS1 (jmp, %2);
1955 break;
1957 else if (l == 0)
1959 if (h == 1)
1960 OUT_AS2 (dec, w, %H0);
1961 else
1963 OUT_AS2 (mov, w, %H0);
1964 OUT_AS2 (sub, w, %H1);
1966 OUT_AS2 (or, w, %L0);
1967 OUT_AS1 (snz,);
1968 OUT_AS1 (page, %2);
1969 OUT_AS1 (jmp, %2);
1970 break;
1974 OUT_AS2 (mov, w, %H1);
1975 OUT_AS2 (cse, w, %H0);
1976 OUT_AS1 (page, 2f);
1977 OUT_AS1 (jmp, 2f);
1978 if (! imm_cmp || (h != l))
1979 OUT_AS2 (mov, w, %L1);
1980 OUT_AS2 (csne, w, %L0);
1981 OUT_AS1 (page, %2);
1982 OUT_AS1 (jmp, %2);
1983 OUT_AS1 (2:,);
1985 break;
1987 case NE:
1989 unsigned char h = 0, l = 1;
1991 if (imm_cmp)
1993 h = (INTVAL (operands[1]) >> 8) & 0xff;
1994 l = INTVAL (operands[1]) & 0xff;
1996 if ((h == 0xff) && (l == 0xff))
1998 OUT_AS2 (incsnz, w, %L0);
1999 OUT_AS2 (incsz, w, %H0);
2000 OUT_AS1 (page, %2);
2001 OUT_AS1 (jmp, %2);
2002 break;
2004 else if (h == 0)
2006 if (l == 1)
2007 OUT_AS2 (dec, w, %L0);
2008 else
2010 OUT_AS2 (mov, w, %L0);
2011 OUT_AS2 (sub, w, %L1);
2013 OUT_AS2 (or, w, %H0);
2014 OUT_AS1 (sz,);
2015 OUT_AS1 (page, %2);
2016 OUT_AS1 (jmp, %2);
2017 break;
2019 else if (l == 0)
2021 if (h == 1)
2022 OUT_AS2 (dec, w, %H0);
2023 else
2025 OUT_AS2 (mov, w, %H0);
2026 OUT_AS2 (sub, w, %H1);
2028 OUT_AS2 (or, w, %L0);
2029 OUT_AS1 (sz,);
2030 OUT_AS1 (page, %2);
2031 OUT_AS1 (jmp, %2);
2032 break;
2036 OUT_AS2 (mov, w, %H1);
2037 if (imm_cmp && (h == l))
2039 OUT_AS2 (csne, w, %H0);
2040 OUT_AS2 (cse, w, %L0);
2042 else
2044 OUT_AS2 (cse, w, %H0);
2045 OUT_AS1 (page, %2);
2046 OUT_AS1 (jmp, %2);
2047 OUT_AS2 (mov, w, %L1);
2048 OUT_AS2 (cse, w, %L0);
2050 OUT_AS1 (page, %2);
2051 OUT_AS1 (jmp, %2);
2053 break;
2055 case GTU:
2056 if (imm_sub)
2058 /* > 0xffff never succeeds! */
2059 if ((INTVAL (operands[1]) & 0xffff) != 0xffff)
2061 operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2062 OUT_AS2 (mov, w, %L3);
2063 OUT_AS2 (sub, w, %L0);
2064 OUT_AS2 (mov, w, %H3);
2065 OUT_AS2 (subc, w, %H0);
2066 OUT_AS1 (snc,);
2067 OUT_AS1 (page, %2);
2068 OUT_AS1 (jmp, %2);
2071 else
2073 OUT_AS2 (mov, w, %L0);
2074 OUT_AS2 (sub, w, %L1);
2075 OUT_AS2 (mov, w, %H0);
2076 OUT_AS2 (subc, w, %H1);
2077 OUT_AS1 (sc,);
2078 OUT_AS1 (page, %2);
2079 OUT_AS1 (jmp, %2);
2081 break;
2083 case GEU:
2084 if (imm_sub)
2086 if (INTVAL (operands[0]) == 0)
2088 OUT_AS2 (mov, w, %H1);
2089 OUT_AS2 (or, w, %L1);
2090 OUT_AS1 (snz,);
2091 OUT_AS1 (page, %2);
2092 OUT_AS1 (jmp, %2);
2094 else
2096 operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2097 OUT_AS2 (mov, w, %L3);
2098 OUT_AS2 (sub, w, %L1);
2099 OUT_AS2 (mov, w, %H3);
2100 OUT_AS2 (subc, w, %H1);
2101 OUT_AS1 (sc,);
2102 OUT_AS1 (page, %2);
2103 OUT_AS1 (jmp, %2);
2106 else
2108 OUT_AS2 (mov, w, %L1);
2109 OUT_AS2 (sub, w, %L0);
2110 OUT_AS2 (mov, w, %H1);
2111 OUT_AS2 (subc, w, %H0);
2112 OUT_AS1 (snc,);
2113 OUT_AS1 (page, %2);
2114 OUT_AS1 (jmp, %2);
2116 break;
2118 case LTU:
2119 if (imm_sub)
2121 if (INTVAL (operands[0]) == 0)
2123 OUT_AS2 (mov, w, %H1);
2124 OUT_AS2 (or, w, %L1);
2125 OUT_AS1 (sz,);
2126 OUT_AS1 (page, %2);
2127 OUT_AS1 (jmp, %2);
2129 else
2131 operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2132 OUT_AS2 (mov, w, %L3);
2133 OUT_AS2 (sub, w, %L1);
2134 OUT_AS2 (mov, w, %H3);
2135 OUT_AS2 (subc, w, %H1);
2136 OUT_AS1 (snc,);
2137 OUT_AS1 (page, %2);
2138 OUT_AS1 (jmp, %2);
2141 else
2143 OUT_AS2 (mov, w, %L1);
2144 OUT_AS2 (sub, w, %L0);
2145 OUT_AS2 (mov, w, %H1);
2146 OUT_AS2 (subc, w, %H0);
2147 OUT_AS1 (sc,);
2148 OUT_AS1 (page, %2);
2149 OUT_AS1 (jmp, %2);
2151 break;
2153 case LEU:
2154 if (imm_sub)
2156 if ((INTVAL (operands[1]) & 0xffff) == 0xffff)
2158 /* <= 0xffff always succeeds. */
2159 OUT_AS1 (page, %2);
2160 OUT_AS1 (jmp, %2);
2162 else
2164 operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2165 OUT_AS2 (mov, w, %L3);
2166 OUT_AS2 (sub, w, %L0);
2167 OUT_AS2 (mov, w, %H3);
2168 OUT_AS2 (subc, w, %H0);
2169 OUT_AS1 (sc,);
2170 OUT_AS1 (page, %2);
2171 OUT_AS1 (jmp, %2);
2174 else
2176 OUT_AS2 (mov, w, %L0);
2177 OUT_AS2 (sub, w, %L1);
2178 OUT_AS2 (mov, w, %H0);
2179 OUT_AS2 (subc, w, %H1);
2180 OUT_AS1 (snc,);
2181 OUT_AS1 (page, %2);
2182 OUT_AS1 (jmp, %2);
2184 break;
2186 default:
2187 abort ();
2189 break;
2191 case SImode:
2192 switch (code)
2194 case EQ:
2196 unsigned char a = 0, b = 1, c = 2, d = 3;
2198 if (imm_cmp)
2200 a = (INTVAL (operands[1]) >> 24) & 0xff;
2201 b = (INTVAL (operands[1]) >> 16) & 0xff;
2202 c = (INTVAL (operands[1]) >> 8) & 0xff;
2203 d = INTVAL (operands[1]) & 0xff;
2206 OUT_AS2 (mov, w, %A1);
2207 if (imm_cmp && (b == a))
2209 OUT_AS2 (csne, w, %A0);
2210 OUT_AS2 (cse, w, %B0);
2212 else
2214 OUT_AS2 (cse, w, %A0);
2215 OUT_AS1 (page, 2f);
2216 OUT_AS1 (jmp, 2f);
2217 OUT_AS2 (mov, w, %B1);
2218 OUT_AS2 (cse, w, %B0);
2220 OUT_AS1 (page, 2f);
2221 OUT_AS1 (jmp, 2f);
2222 if (! imm_cmp || (c != b))
2223 OUT_AS2 (mov, w, %C1);
2224 OUT_AS2 (cse, w, %C0);
2225 OUT_AS1 (page, 2f);
2226 OUT_AS1 (jmp, 2f);
2227 if (! imm_cmp || (d != c))
2228 OUT_AS2 (mov, w, %D1);
2229 OUT_AS2 (csne, w, %D0);
2230 OUT_AS1 (page, %2);
2231 OUT_AS1 (jmp, %2);
2232 OUT_AS1 (2:,);
2234 break;
2236 case NE:
2238 unsigned char a = 0, b = 1, c = 2, d = 3;
2240 if (imm_cmp)
2242 a = (INTVAL (operands[1]) >> 24) & 0xff;
2243 b = (INTVAL (operands[1]) >> 16) & 0xff;
2244 c = (INTVAL (operands[1]) >> 8) & 0xff;
2245 d = INTVAL (operands[1]) & 0xff;
2248 OUT_AS2 (mov, w, %A1);
2249 if (imm_cmp && (b == a))
2251 OUT_AS2 (csne, w, %A0);
2252 OUT_AS2 (cse, w, %B0);
2254 else
2256 OUT_AS2 (cse, w, %A0);
2257 OUT_AS1 (page, %2);
2258 OUT_AS1 (jmp, %2);
2259 OUT_AS2 (mov, w, %B1);
2260 OUT_AS2 (cse, w, %B0);
2262 OUT_AS1 (page, %2);
2263 OUT_AS1 (jmp, %2);
2264 if (! imm_cmp || (c != b))
2265 OUT_AS2 (mov, w, %C1);
2266 if (imm_cmp && (d == c))
2268 OUT_AS2 (csne, w, %C0);
2269 OUT_AS2 (cse, w, %D0);
2271 else
2273 OUT_AS2 (cse, w, %C0);
2274 OUT_AS1 (page, %2);
2275 OUT_AS1 (jmp, %2);
2276 OUT_AS2 (mov, w, %D1);
2277 OUT_AS2 (cse, w, %D0);
2279 OUT_AS1 (page, %2);
2280 OUT_AS1 (jmp, %2);
2282 break;
2284 case GTU:
2285 if (imm_sub)
2287 /* > 0xffffffff never succeeds! */
2288 if ((unsigned HOST_WIDE_INT)(INTVAL (operands[1]) & 0xffffffff)
2289 != 0xffffffff)
2291 operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2292 OUT_AS2 (mov, w, %D3);
2293 OUT_AS2 (sub, w, %D0);
2294 OUT_AS2 (mov, w, %C3);
2295 OUT_AS2 (subc, w, %C0);
2296 OUT_AS2 (mov, w, %B3);
2297 OUT_AS2 (subc, w, %B0);
2298 OUT_AS2 (mov, w, %A3);
2299 OUT_AS2 (subc, w, %A0);
2300 OUT_AS1 (snc,);
2301 OUT_AS1 (page, %2);
2302 OUT_AS1 (jmp, %2);
2305 else
2307 OUT_AS2 (mov, w, %D0);
2308 OUT_AS2 (sub, w, %D1);
2309 OUT_AS2 (mov, w, %C0);
2310 OUT_AS2 (subc, w, %C1);
2311 OUT_AS2 (mov, w, %B0);
2312 OUT_AS2 (subc, w, %B1);
2313 OUT_AS2 (mov, w, %A0);
2314 OUT_AS2 (subc, w, %A1);
2315 OUT_AS1 (sc,);
2316 OUT_AS1 (page, %2);
2317 OUT_AS1 (jmp, %2);
2319 break;
2321 case GEU:
2322 if (imm_sub)
2324 if (INTVAL (operands[0]) == 0)
2326 OUT_AS2 (mov, w, %A1);
2327 OUT_AS2 (or, w, %B1);
2328 OUT_AS2 (or, w, %C1);
2329 OUT_AS2 (or, w, %D1);
2330 OUT_AS1 (snz,);
2331 OUT_AS1 (page, %2);
2332 OUT_AS1 (jmp, %2);
2334 else
2336 operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2337 OUT_AS2 (mov, w, %D3);
2338 OUT_AS2 (sub, w, %D1);
2339 OUT_AS2 (mov, w, %C3);
2340 OUT_AS2 (subc, w, %C1);
2341 OUT_AS2 (mov, w, %B3);
2342 OUT_AS2 (subc, w, %B1);
2343 OUT_AS2 (mov, w, %A3);
2344 OUT_AS2 (subc, w, %A1);
2345 OUT_AS1 (sc,);
2346 OUT_AS1 (page, %2);
2347 OUT_AS1 (jmp, %2);
2350 else
2352 OUT_AS2 (mov, w, %D1);
2353 OUT_AS2 (sub, w, %D0);
2354 OUT_AS2 (mov, w, %C1);
2355 OUT_AS2 (subc, w, %C0);
2356 OUT_AS2 (mov, w, %B1);
2357 OUT_AS2 (subc, w, %B0);
2358 OUT_AS2 (mov, w, %A1);
2359 OUT_AS2 (subc, w, %A0);
2360 OUT_AS1 (snc,);
2361 OUT_AS1 (page, %2);
2362 OUT_AS1 (jmp, %2);
2364 break;
2366 case LTU:
2367 if (imm_sub)
2369 if (INTVAL (operands[0]) == 0)
2371 OUT_AS2 (mov, w, %A1);
2372 OUT_AS2 (or, w, %B1);
2373 OUT_AS2 (or, w, %C1);
2374 OUT_AS2 (or, w, %D1);
2375 OUT_AS1 (sz,);
2376 OUT_AS1 (page, %2);
2377 OUT_AS1 (jmp, %2);
2379 else
2381 operands[3] = GEN_INT (INTVAL (operands[0]) - 1);
2382 OUT_AS2 (mov, w, %D3);
2383 OUT_AS2 (sub, w, %D1);
2384 OUT_AS2 (mov, w, %C3);
2385 OUT_AS2 (subc, w, %C1);
2386 OUT_AS2 (mov, w, %B3);
2387 OUT_AS2 (subc, w, %B1);
2388 OUT_AS2 (mov, w, %A3);
2389 OUT_AS2 (subc, w, %A1);
2390 OUT_AS1 (snc,);
2391 OUT_AS1 (page, %2);
2392 OUT_AS1 (jmp, %2);
2395 else
2397 OUT_AS2 (mov, w, %D1);
2398 OUT_AS2 (sub, w, %D0);
2399 OUT_AS2 (mov, w, %C1);
2400 OUT_AS2 (subc, w, %C0);
2401 OUT_AS2 (mov, w, %B1);
2402 OUT_AS2 (subc, w, %B0);
2403 OUT_AS2 (mov, w, %A1);
2404 OUT_AS2 (subc, w, %A0);
2405 OUT_AS1 (sc,);
2406 OUT_AS1 (page, %2);
2407 OUT_AS1 (jmp, %2);
2409 break;
2411 case LEU:
2412 if (imm_sub)
2414 if ((unsigned HOST_WIDE_INT)(INTVAL (operands[1]) & 0xffffffff)
2415 == 0xffffffff)
2417 /* <= 0xffffffff always succeeds. */
2418 OUT_AS1 (page, %2);
2419 OUT_AS1 (jmp, %2);
2421 else
2423 operands[3] = GEN_INT (INTVAL (operands[1]) + 1);
2424 OUT_AS2 (mov, w, %D3);
2425 OUT_AS2 (sub, w, %D0);
2426 OUT_AS2 (mov, w, %C3);
2427 OUT_AS2 (subc, w, %C0);
2428 OUT_AS2 (mov, w, %B3);
2429 OUT_AS2 (subc, w, %B0);
2430 OUT_AS2 (mov, w, %A3);
2431 OUT_AS2 (subc, w, %A0);
2432 OUT_AS1 (sc,);
2433 OUT_AS1 (page, %2);
2434 OUT_AS1 (jmp, %2);
2437 else
2439 OUT_AS2 (mov, w, %D0);
2440 OUT_AS2 (sub, w, %D1);
2441 OUT_AS2 (mov, w, %C0);
2442 OUT_AS2 (subc, w, %C1);
2443 OUT_AS2 (mov, w, %B0);
2444 OUT_AS2 (subc, w, %B1);
2445 OUT_AS2 (mov, w, %A0);
2446 OUT_AS2 (subc, w, %A1);
2447 OUT_AS1 (snc,);
2448 OUT_AS1 (page, %2);
2449 OUT_AS1 (jmp, %2);
2451 break;
2453 default:
2454 abort ();
2456 break;
2458 case DImode:
2459 if (GET_CODE (operands[1]) == CONST_INT)
2461 const_low = INTVAL (operands[1]);
2462 const_high = (const_low >= 0) - 1;
2464 else if (GET_CODE (operands[1]) == CONST_DOUBLE)
2466 const_low = CONST_DOUBLE_LOW (operands[1]);
2467 const_high = CONST_DOUBLE_HIGH (operands[1]);
2469 switch (code)
2471 case EQ:
2473 unsigned char s = 0, t = 1, u = 2, v = 3;
2474 unsigned char w = 4, x = 5, y = 6, z = 7;
2475 if (optimize_size)
2477 if (GET_CODE (operands[0]) == MEM
2478 && true_regnum (XEXP (operands[0], 0)) == REG_DP)
2480 OUT_AS1 (push, %Z1%<);
2481 OUT_AS1 (push, %Y1%<);
2482 OUT_AS1 (push, %X1%<);
2483 OUT_AS1 (push, %W1%<);
2484 OUT_AS1 (push, %V1%<);
2485 OUT_AS1 (push, %U1%<);
2486 OUT_AS1 (push, %T1%<);
2487 OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
2488 OUT_AS1 (page, __cmpdi2_dp);
2489 OUT_AS1 (call, __cmpdi2_dp);
2490 OUT_AS2 (csne, w, #1);
2491 OUT_AS1 (page, %2);
2492 OUT_AS1 (jmp, %2);
2494 else
2496 OUT_AS1 (push, %Z1%<);
2497 OUT_AS1 (push, %Y1%<);
2498 OUT_AS1 (push, %X1%<);
2499 OUT_AS1 (push, %W1%<);
2500 OUT_AS1 (push, %V1%<);
2501 OUT_AS1 (push, %U1%<);
2502 OUT_AS1 (push, %T1%<);
2503 OUT_AS1 (push, %S1%<);
2504 OUT_AS1 (push, %Z0%<);
2505 OUT_AS1 (push, %Y0%<);
2506 OUT_AS1 (push, %X0%<);
2507 OUT_AS1 (push, %W0%<);
2508 OUT_AS1 (push, %V0%<);
2509 OUT_AS1 (push, %U0%<);
2510 OUT_AS1 (push, %T0%<);
2511 OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
2512 OUT_AS1 (page, __cmpdi2);
2513 OUT_AS1 (call, __cmpdi2);
2514 OUT_AS2 (csne, w, #1);
2515 OUT_AS1 (page, %2);
2516 OUT_AS1 (jmp, %2);
2519 else
2521 if (imm_cmp)
2523 s = (const_high >> 24) & 0xff;
2524 t = (const_high >> 16) & 0xff;
2525 u = (const_high >> 8) & 0xff;
2526 v = const_high & 0xff;
2527 w = (const_low >> 24) & 0xff;
2528 x = (const_low >> 16) & 0xff;
2529 y = (const_low >> 8) & 0xff;
2530 z = const_low & 0xff;
2533 OUT_AS2 (mov, w, %S1);
2534 if (imm_cmp && (s == t))
2536 OUT_AS2 (csne, w, %S0);
2537 OUT_AS2 (cse, w, %T0);
2539 else
2541 OUT_AS2 (cse, w, %S0);
2542 OUT_AS1 (page, 2f);
2543 OUT_AS1 (jmp, 2f);
2544 OUT_AS2 (mov, w, %T1);
2545 OUT_AS2 (cse, w, %T0);
2547 OUT_AS1 (page, 2f);
2548 OUT_AS1 (jmp, 2f);
2550 OUT_AS2 (mov, w, %U1);
2551 if (imm_cmp && (u == v))
2553 OUT_AS2 (csne, w, %U0);
2554 OUT_AS2 (cse, w, %V0);
2556 else
2558 OUT_AS2 (cse, w, %U0);
2559 OUT_AS1 (page, 2f);
2560 OUT_AS1 (jmp, 2f);
2561 OUT_AS2 (mov, w, %V1);
2562 OUT_AS2 (cse, w, %V0);
2564 OUT_AS1 (page, 2f);
2565 OUT_AS1 (jmp, 2f);
2567 OUT_AS2 (mov, w, %W1);
2568 if (imm_cmp && (w == x))
2570 OUT_AS2 (csne, w, %W0);
2571 OUT_AS2 (cse, w, %X0);
2573 else
2575 OUT_AS2 (cse, w, %W0);
2576 OUT_AS1 (page, 2f);
2577 OUT_AS1 (jmp, 2f);
2578 OUT_AS2 (mov, w, %X1);
2579 OUT_AS2 (cse, w, %X0);
2581 OUT_AS1 (page, 2f);
2582 OUT_AS1 (jmp, 2f);
2584 if (! imm_cmp || (x != y))
2585 OUT_AS2 (mov, w, %Y1);
2586 OUT_AS2 (cse, w, %Y0);
2587 OUT_AS1 (page, 2f);
2588 OUT_AS1 (jmp, 2f);
2589 if (! imm_cmp || (z != y))
2590 OUT_AS2 (mov, w, %Z1);
2591 OUT_AS2 (csne, w, %Z0);
2592 OUT_AS1 (page, %2);
2593 OUT_AS1 (jmp, %2);
2594 OUT_AS1 (2:,);
2597 break;
2599 case NE:
2601 unsigned char s = 0, t = 1, u = 2, v = 3;
2602 unsigned char w = 4, x = 5, y = 6, z = 7;
2604 if (optimize_size)
2606 if (GET_CODE (operands[0]) == MEM
2607 && true_regnum (XEXP (operands[0], 0)) == REG_DP)
2609 OUT_AS1 (push, %Z1%<);
2610 OUT_AS1 (push, %Y1%<);
2611 OUT_AS1 (push, %X1%<);
2612 OUT_AS1 (push, %W1%<);
2613 OUT_AS1 (push, %V1%<);
2614 OUT_AS1 (push, %U1%<);
2615 OUT_AS1 (push, %T1%<);
2616 OUT_AS1 (push, %S1%>%>%>%>%>%>%>);
2617 OUT_AS1 (page, __cmpdi2_dp);
2618 OUT_AS1 (call, __cmpdi2_dp);
2619 OUT_AS2 (cse, w, #1);
2620 OUT_AS1 (page, %2);
2621 OUT_AS1 (jmp, %2);
2623 else
2625 OUT_AS1 (push, %Z1%<);
2626 OUT_AS1 (push, %Y1%<);
2627 OUT_AS1 (push, %X1%<);
2628 OUT_AS1 (push, %W1%<);
2629 OUT_AS1 (push, %V1%<);
2630 OUT_AS1 (push, %U1%<);
2631 OUT_AS1 (push, %T1%<);
2632 OUT_AS1 (push, %S1%<);
2633 OUT_AS1 (push, %Z0%<);
2634 OUT_AS1 (push, %Y0%<);
2635 OUT_AS1 (push, %X0%<);
2636 OUT_AS1 (push, %W0%<);
2637 OUT_AS1 (push, %V0%<);
2638 OUT_AS1 (push, %U0%<);
2639 OUT_AS1 (push, %T0%<);
2640 OUT_AS1 (push, %S0%>%>%>%>%>%>%>%>%>%>%>%>%>%>%>);
2641 OUT_AS1 (page, __cmpdi2);
2642 OUT_AS1 (call, __cmpdi2);
2643 OUT_AS2 (cse, w, #1);
2644 OUT_AS1 (page, %2);
2645 OUT_AS1 (jmp, %2);
2648 else
2650 if (imm_cmp)
2652 s = (const_high >> 24) & 0xff;
2653 t = (const_high >> 16) & 0xff;
2654 u = (const_high >> 8) & 0xff;
2655 v = const_high & 0xff;
2656 w = (const_low >> 24) & 0xff;
2657 x = (const_low >> 16) & 0xff;
2658 y = (const_low >> 8) & 0xff;
2659 z = const_low & 0xff;
2662 OUT_AS2 (mov, w, %S1);
2663 if (imm_cmp && (s == t))
2665 OUT_AS2 (csne, w, %S0);
2666 OUT_AS2 (cse, w, %T0);
2668 else
2670 OUT_AS2 (cse, w, %S0);
2671 OUT_AS1 (page, %2);
2672 OUT_AS1 (jmp, %2);
2673 OUT_AS2 (mov, w, %T1);
2674 OUT_AS2 (cse, w, %T0);
2676 OUT_AS1 (page, %2);
2677 OUT_AS1 (jmp, %2);
2679 OUT_AS2 (mov, w, %U1);
2680 if (imm_cmp && (u == v))
2682 OUT_AS2 (csne, w, %U0);
2683 OUT_AS2 (cse, w, %V0);
2685 else
2687 OUT_AS2 (cse, w, %U0);
2688 OUT_AS1 (page, %2);
2689 OUT_AS1 (jmp, %2);
2690 OUT_AS2 (mov, w, %V1);
2691 OUT_AS2 (cse, w, %V0);
2693 OUT_AS1 (page, %2);
2694 OUT_AS1 (jmp, %2);
2696 OUT_AS2 (mov, w, %W1);
2697 if (imm_cmp && (w == x))
2699 OUT_AS2 (csne, w, %W0);
2700 OUT_AS2 (cse, w, %X0);
2702 else
2704 OUT_AS2 (cse, w, %W0);
2705 OUT_AS1 (page, %2);
2706 OUT_AS1 (jmp, %2);
2707 OUT_AS2 (mov, w, %X1);
2708 OUT_AS2 (cse, w, %X0);
2710 OUT_AS1 (page, %2);
2711 OUT_AS1 (jmp, %2);
2713 if (! imm_cmp || (y != x))
2714 OUT_AS2 (mov, w, %Y1);
2715 if (imm_cmp && (z == y))
2717 OUT_AS2 (csne, w, %Y0);
2718 OUT_AS2 (cse, w, %Z0);
2720 else
2722 OUT_AS2 (cse, w, %Y0);
2723 OUT_AS1 (page, %2);
2724 OUT_AS1 (jmp, %2);
2725 OUT_AS2 (mov, w, %Z1);
2726 OUT_AS2 (cse, w, %Z0);
2728 OUT_AS1 (page, %2);
2729 OUT_AS1 (jmp, %2);
2732 break;
2734 case GTU:
2735 if (imm_sub)
2737 /* > 0xffffffffffffffff never succeeds! */
2738 if (((const_high & 0xffffffff) != 0xffffffff)
2739 || ((const_low & 0xffffffff) != 0xffffffff))
2741 operands[3] = GEN_INT (const_low + 1);
2742 operands[4] = GEN_INT (const_high
2743 + (INTVAL (operands[3]) ? 0 : 1));
2744 OUT_AS2 (mov, w, %D3);
2745 OUT_AS2 (sub, w, %Z0);
2746 OUT_AS2 (mov, w, %C3);
2747 OUT_AS2 (subc, w, %Y0);
2748 OUT_AS2 (mov, w, %B3);
2749 OUT_AS2 (subc, w, %X0);
2750 OUT_AS2 (mov, w, %A3);
2751 OUT_AS2 (subc, w, %W0);
2752 OUT_AS2 (mov, w, %D4);
2753 OUT_AS2 (subc, w, %V0);
2754 OUT_AS2 (mov, w, %C4);
2755 OUT_AS2 (subc, w, %U0);
2756 OUT_AS2 (mov, w, %B4);
2757 OUT_AS2 (subc, w, %T0);
2758 OUT_AS2 (mov, w, %A4);
2759 OUT_AS2 (subc, w, %S0);
2760 OUT_AS1 (snc,);
2761 OUT_AS1 (page, %2);
2762 OUT_AS1 (jmp, %2);
2765 else
2767 OUT_AS2 (mov, w, %Z0);
2768 OUT_AS2 (sub, w, %Z1);
2769 OUT_AS2 (mov, w, %Y0);
2770 OUT_AS2 (subc, w, %Y1);
2771 OUT_AS2 (mov, w, %X0);
2772 OUT_AS2 (subc, w, %X1);
2773 OUT_AS2 (mov, w, %W0);
2774 OUT_AS2 (subc, w, %W1);
2775 OUT_AS2 (mov, w, %V0);
2776 OUT_AS2 (subc, w, %V1);
2777 OUT_AS2 (mov, w, %U0);
2778 OUT_AS2 (subc, w, %U1);
2779 OUT_AS2 (mov, w, %T0);
2780 OUT_AS2 (subc, w, %T1);
2781 OUT_AS2 (mov, w, %S0);
2782 OUT_AS2 (subc, w, %S1);
2783 OUT_AS1 (sc,);
2784 OUT_AS1 (page, %2);
2785 OUT_AS1 (jmp, %2);
2787 break;
2789 case GEU:
2790 if (imm_sub)
2792 HOST_WIDE_INT const_low0;
2793 HOST_WIDE_INT const_high0;
2795 if (GET_CODE (operands[0]) == CONST_INT)
2797 const_low0 = INTVAL (operands[0]);
2798 const_high0 = (const_low >= 0) - 1;
2800 else if (GET_CODE (operands[0]) == CONST_DOUBLE)
2802 const_low0 = CONST_DOUBLE_LOW (operands[0]);
2803 const_high0 = CONST_DOUBLE_HIGH (operands[0]);
2806 if (const_high0 == 0 && const_low0 == 0)
2808 OUT_AS2 (mov, w, %S1);
2809 OUT_AS2 (or, w, %T1);
2810 OUT_AS2 (or, w, %U1);
2811 OUT_AS2 (or, w, %V1);
2812 OUT_AS2 (or, w, %W1);
2813 OUT_AS2 (or, w, %X1);
2814 OUT_AS2 (or, w, %Y1);
2815 OUT_AS2 (or, w, %Z1);
2816 OUT_AS1 (snz,);
2817 OUT_AS1 (page, %2);
2818 OUT_AS1 (jmp, %2);
2820 else
2822 operands[3] = GEN_INT (const_low0 - 1);
2823 operands[4] = GEN_INT (const_high0 - (const_low0 ? 1 : 0));
2824 OUT_AS2 (mov, w, %D3);
2825 OUT_AS2 (sub, w, %Z1);
2826 OUT_AS2 (mov, w, %C3);
2827 OUT_AS2 (subc, w, %Y1);
2828 OUT_AS2 (mov, w, %B3);
2829 OUT_AS2 (subc, w, %X1);
2830 OUT_AS2 (mov, w, %A3);
2831 OUT_AS2 (subc, w, %W1);
2832 OUT_AS2 (mov, w, %D4);
2833 OUT_AS2 (subc, w, %V1);
2834 OUT_AS2 (mov, w, %C4);
2835 OUT_AS2 (subc, w, %U1);
2836 OUT_AS2 (mov, w, %B4);
2837 OUT_AS2 (subc, w, %T1);
2838 OUT_AS2 (mov, w, %A4);
2839 OUT_AS2 (subc, w, %S1);
2840 OUT_AS1 (sc,);
2841 OUT_AS1 (page, %2);
2842 OUT_AS1 (jmp, %2);
2845 else
2847 OUT_AS2 (mov, w, %Z1);
2848 OUT_AS2 (sub, w, %Z0);
2849 OUT_AS2 (mov, w, %Y1);
2850 OUT_AS2 (subc, w, %Y0);
2851 OUT_AS2 (mov, w, %X1);
2852 OUT_AS2 (subc, w, %X0);
2853 OUT_AS2 (mov, w, %W1);
2854 OUT_AS2 (subc, w, %W0);
2855 OUT_AS2 (mov, w, %V1);
2856 OUT_AS2 (subc, w, %V0);
2857 OUT_AS2 (mov, w, %U1);
2858 OUT_AS2 (subc, w, %U0);
2859 OUT_AS2 (mov, w, %T1);
2860 OUT_AS2 (subc, w, %T0);
2861 OUT_AS2 (mov, w, %S1);
2862 OUT_AS2 (subc, w, %S0);
2863 OUT_AS1 (snc,);
2864 OUT_AS1 (page, %2);
2865 OUT_AS1 (jmp, %2);
2867 break;
2869 case LTU:
2870 if (imm_sub)
2872 HOST_WIDE_INT const_low0;
2873 HOST_WIDE_INT const_high0;
2875 if (GET_CODE (operands[0]) == CONST_INT)
2877 const_low0 = INTVAL (operands[0]);
2878 const_high0 = (const_low >= 0) - 1;
2880 else if (GET_CODE (operands[0]) == CONST_DOUBLE)
2882 const_low0 = CONST_DOUBLE_LOW (operands[0]);
2883 const_high0 = CONST_DOUBLE_HIGH (operands[0]);
2886 if (const_high0 == 0 && const_low0 == 0)
2888 OUT_AS2 (mov, w, %S1);
2889 OUT_AS2 (or, w, %T1);
2890 OUT_AS2 (or, w, %U1);
2891 OUT_AS2 (or, w, %V1);
2892 OUT_AS2 (or, w, %W1);
2893 OUT_AS2 (or, w, %X1);
2894 OUT_AS2 (or, w, %Y1);
2895 OUT_AS2 (or, w, %Z1);
2896 OUT_AS1 (sz,);
2897 OUT_AS1 (page, %2);
2898 OUT_AS1 (jmp, %2);
2900 else
2902 operands[3] = GEN_INT (const_low0 - 1);
2903 operands[4] = GEN_INT (const_high0 - (const_low0 ? 1 : 0));
2904 OUT_AS2 (mov, w, %D3);
2905 OUT_AS2 (sub, w, %Z1);
2906 OUT_AS2 (mov, w, %C3);
2907 OUT_AS2 (subc, w, %Y1);
2908 OUT_AS2 (mov, w, %B3);
2909 OUT_AS2 (subc, w, %X1);
2910 OUT_AS2 (mov, w, %A3);
2911 OUT_AS2 (subc, w, %W1);
2912 OUT_AS2 (mov, w, %D4);
2913 OUT_AS2 (subc, w, %V1);
2914 OUT_AS2 (mov, w, %C4);
2915 OUT_AS2 (subc, w, %U1);
2916 OUT_AS2 (mov, w, %B4);
2917 OUT_AS2 (subc, w, %T1);
2918 OUT_AS2 (mov, w, %A4);
2919 OUT_AS2 (subc, w, %S1);
2920 OUT_AS1 (snc,);
2921 OUT_AS1 (page, %2);
2922 OUT_AS1 (jmp, %2);
2925 else
2927 OUT_AS2 (mov, w, %Z1);
2928 OUT_AS2 (sub, w, %Z0);
2929 OUT_AS2 (mov, w, %Y1);
2930 OUT_AS2 (subc, w, %Y0);
2931 OUT_AS2 (mov, w, %X1);
2932 OUT_AS2 (subc, w, %X0);
2933 OUT_AS2 (mov, w, %W1);
2934 OUT_AS2 (subc, w, %W0);
2935 OUT_AS2 (mov, w, %V1);
2936 OUT_AS2 (subc, w, %V0);
2937 OUT_AS2 (mov, w, %U1);
2938 OUT_AS2 (subc, w, %U0);
2939 OUT_AS2 (mov, w, %T1);
2940 OUT_AS2 (subc, w, %T0);
2941 OUT_AS2 (mov, w, %S1);
2942 OUT_AS2 (subc, w, %S0);
2943 OUT_AS1 (sc,);
2944 OUT_AS1 (page, %2);
2945 OUT_AS1 (jmp, %2);
2947 break;
2949 case LEU:
2950 if (imm_sub)
2952 if (((const_high & 0xffffffff) == 0xffffffff)
2953 && ((const_low & 0xffffffff) == 0xffffffff))
2955 /* <= 0xffffffffffffffff always succeeds. */
2956 OUT_AS1 (page, %2);
2957 OUT_AS1 (jmp, %2);
2959 else
2961 operands[3] = GEN_INT (const_low + 1);
2962 operands[4] = GEN_INT (const_high
2963 + (INTVAL (operands[3]) ? 0 : 1));
2964 OUT_AS2 (mov, w, %D3);
2965 OUT_AS2 (sub, w, %Z0);
2966 OUT_AS2 (mov, w, %C3);
2967 OUT_AS2 (subc, w, %Y0);
2968 OUT_AS2 (mov, w, %B3);
2969 OUT_AS2 (subc, w, %X0);
2970 OUT_AS2 (mov, w, %A3);
2971 OUT_AS2 (subc, w, %W0);
2972 OUT_AS2 (mov, w, %D4);
2973 OUT_AS2 (subc, w, %V0);
2974 OUT_AS2 (mov, w, %C4);
2975 OUT_AS2 (subc, w, %U0);
2976 OUT_AS2 (mov, w, %B4);
2977 OUT_AS2 (subc, w, %T0);
2978 OUT_AS2 (mov, w, %A4);
2979 OUT_AS2 (subc, w, %S0);
2980 OUT_AS1 (sc,);
2981 OUT_AS1 (page, %2);
2982 OUT_AS1 (jmp, %2);
2985 else
2987 OUT_AS2 (mov, w, %Z0);
2988 OUT_AS2 (sub, w, %Z1);
2989 OUT_AS2 (mov, w, %Y0);
2990 OUT_AS2 (subc, w, %Y1);
2991 OUT_AS2 (mov, w, %X0);
2992 OUT_AS2 (subc, w, %X1);
2993 OUT_AS2 (mov, w, %W0);
2994 OUT_AS2 (subc, w, %W1);
2995 OUT_AS2 (mov, w, %V0);
2996 OUT_AS2 (subc, w, %V1);
2997 OUT_AS2 (mov, w, %U0);
2998 OUT_AS2 (subc, w, %U1);
2999 OUT_AS2 (mov, w, %T0);
3000 OUT_AS2 (subc, w, %T1);
3001 OUT_AS2 (mov, w, %S0);
3002 OUT_AS2 (subc, w, %S1);
3003 OUT_AS1 (snc,);
3004 OUT_AS1 (page, %2);
3005 OUT_AS1 (jmp, %2);
3007 break;
3009 default:
3010 abort ();
3012 break;
3014 default:
3015 abort ();
3017 #undef operands
3018 return "";
3021 /* Output rtx VALUE as .byte to file FILE. */
3023 void
3024 asm_output_char (FILE *file, rtx value)
3026 fprintf (file, "\t.byte ");
3027 output_addr_const (file, value);
3028 fprintf (file, "\n");
3032 /* Output VALUE as .byte to file FILE. */
3034 void
3035 asm_output_byte (FILE *file, int value)
3037 fprintf (file, "\t.byte 0x%x\n",value & 0xff);
3041 /* Output rtx VALUE as .word to file FILE. */
3043 void
3044 asm_output_short (FILE *file, rtx value)
3046 fprintf (file, "\t.word ");
3047 output_addr_const (file, (value));
3048 fprintf (file, "\n");
3052 /* Output real N to file FILE. */
3054 void
3055 asm_output_float (FILE *file, REAL_VALUE_TYPE n)
3057 long val;
3058 char dstr[100];
3060 REAL_VALUE_TO_TARGET_SINGLE (n, val);
3061 real_to_decimal (dstr, &n, sizeof (dstr), 0, 1);
3063 fprintf (file, "\t.long 0x%08lx\t/* %s */\n", val, dstr);
3066 /* Sets section name for declaration DECL. */
3068 void
3069 unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
3071 int len;
3072 const char *name;
3073 char *string;
3074 const char *prefix;
3075 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
3076 /* Strip off any encoding in name. */
3077 name = (* targetm.strip_name_encoding) (name);
3079 if (TREE_CODE (decl) == FUNCTION_DECL)
3081 if (flag_function_sections)
3082 prefix = ".text.";
3083 else
3084 prefix = ".text";
3086 else
3087 abort ();
3089 if (flag_function_sections)
3091 len = strlen (name) + strlen (prefix);
3092 string = alloca (len + 1);
3093 sprintf (string, "%s%s", prefix, name);
3094 DECL_SECTION_NAME (decl) = build_string (len, string);
3098 /* Return value is nonzero if pseudos that have been
3099 assigned to registers of class CLASS would likely be spilled
3100 because registers of CLASS are needed for spill registers. */
3102 enum reg_class
3103 class_likely_spilled_p (int c)
3105 return (c == IP_REGS
3106 || c == IPL_REGS
3107 || c == IPH_REGS
3108 || c == DP_SP_REGS
3109 || c == SP_REGS
3110 || c == DP_REGS
3111 || c == DPL_REGS
3112 || c == DPH_REGS
3113 || c == PTR_REGS);
3116 /* Valid attributes:
3117 progmem - put data to program memory;
3118 naked - don't generate function prologue/epilogue and `ret' command.
3120 Only `progmem' attribute valid for type. */
3122 const struct attribute_spec ip2k_attribute_table[] =
3124 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
3125 { "progmem", 0, 0, false, false, false, ip2k_handle_progmem_attribute },
3126 { "naked", 0, 0, true, false, false, ip2k_handle_fndecl_attribute },
3127 { NULL, 0, 0, false, false, false, NULL }
3130 /* Handle a "progmem" attribute; arguments as in
3131 struct attribute_spec.handler. */
3132 static tree
3133 ip2k_handle_progmem_attribute (tree *node, tree name,
3134 tree args ATTRIBUTE_UNUSED,
3135 int flags ATTRIBUTE_UNUSED,
3136 bool *no_add_attrs)
3138 if (DECL_P (*node))
3140 if (TREE_CODE (*node) == TYPE_DECL)
3142 /* This is really a decl attribute, not a type attribute,
3143 but try to handle it for GCC 3.0 backwards compatibility. */
3145 tree type = TREE_TYPE (*node);
3146 tree attr = tree_cons (name, args, TYPE_ATTRIBUTES (type));
3147 tree newtype = build_type_attribute_variant (type, attr);
3149 TYPE_MAIN_VARIANT (newtype) = TYPE_MAIN_VARIANT (type);
3150 TREE_TYPE (*node) = newtype;
3151 *no_add_attrs = true;
3153 else if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
3155 if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node))
3157 warning (0, "only initialized variables can be placed into "
3158 "program memory area");
3159 *no_add_attrs = true;
3162 else
3164 warning (OPT_Wattributes, "%qs attribute ignored",
3165 IDENTIFIER_POINTER (name));
3166 *no_add_attrs = true;
3170 return NULL_TREE;
3173 /* Handle an attribute requiring a FUNCTION_DECL; arguments as in
3174 struct attribute_spec.handler. */
3175 static tree
3176 ip2k_handle_fndecl_attribute (tree *node, tree name,
3177 tree args ATTRIBUTE_UNUSED,
3178 int flags ATTRIBUTE_UNUSED,
3179 bool *no_add_attrs)
3181 if (TREE_CODE (*node) != FUNCTION_DECL)
3183 warning (OPT_Wattributes, "%qs attribute only applies to functions",
3184 IDENTIFIER_POINTER (name));
3185 *no_add_attrs = true;
3188 return NULL_TREE;
3191 /* Cost functions. */
3193 /* Compute a (partial) cost for rtx X. Return true if the complete
3194 cost has been computed, and false if subexpressions should be
3195 scanned. In either case, *TOTAL contains the cost result. */
3197 static bool
3198 ip2k_rtx_costs (rtx x, int code, int outer_code, int *total)
3200 enum machine_mode mode = GET_MODE (x);
3201 int extra_cost = 0;
3203 switch (code)
3205 case CONST_INT:
3206 case CONST_DOUBLE:
3207 case LABEL_REF:
3208 *total = 0;
3209 return true;
3210 case CONST:
3211 case SYMBOL_REF:
3212 *total = 8;
3213 return true;
3215 case MEM:
3216 *total = ip2k_address_cost (XEXP (x, 0));
3217 return true;
3219 case ROTATE:
3220 case ROTATERT:
3221 case ASHIFT:
3222 case LSHIFTRT:
3223 case ASHIFTRT:
3224 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
3226 int val = INTVAL (XEXP (x, 1));
3227 int cost;
3229 /* Shift by const instructions are proportional to
3230 the shift count modulus 8. Note that we increase the mode
3231 size multiplier by 1 to account for clearing the carry flag. */
3232 cost = COSTS_N_INSNS (abs (val) % 8);
3233 cost += rtx_cost (XEXP (x, 0), code);
3234 cost *= (GET_MODE_SIZE (mode) + 1);
3236 /* Sign-preserving shifts require 2 extra instructions. */
3237 if (code == ASHIFT)
3238 cost += COSTS_N_INSNS (2);
3240 *total = cost;
3241 return true;
3243 *total = rtx_cost (XEXP (x, 0), code);
3244 *total += COSTS_N_INSNS (GET_MODE_SIZE (mode) * 8);
3245 return true;
3247 case MINUS:
3248 case PLUS:
3249 case AND:
3250 case XOR:
3251 case IOR:
3252 *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) * 3);
3253 return false;
3255 case MOD:
3256 case DIV:
3257 if (mode == QImode)
3258 *total = COSTS_N_INSNS (20);
3259 else if (mode == HImode)
3260 *total = COSTS_N_INSNS (60);
3261 else if (mode == SImode)
3262 *total = COSTS_N_INSNS (180);
3263 else
3264 *total = COSTS_N_INSNS (540);
3265 return true;
3267 case MULT:
3268 /* These costs are OK, but should really handle subtle cases
3269 where we're using sign or zero extended args as these are
3270 *much* cheaper than those given below! */
3271 if (mode == QImode)
3272 *total = COSTS_N_INSNS (4);
3273 else if (mode == HImode)
3274 *total = COSTS_N_INSNS (12);
3275 else if (mode == SImode)
3276 *total = COSTS_N_INSNS (36);
3277 else
3278 *total = COSTS_N_INSNS (108);
3279 return true;
3281 case NEG:
3282 case SIGN_EXTEND:
3283 extra_cost = COSTS_N_INSNS (GET_MODE_SIZE (mode));
3285 /* Fall through. */
3286 case NOT:
3287 case COMPARE:
3288 case ABS:
3289 *total = extra_cost + COSTS_N_INSNS (GET_MODE_SIZE (mode) * 2);
3290 return false;
3292 case TRUNCATE:
3293 case ZERO_EXTEND:
3294 if (outer_code == SET)
3296 *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) * 3 / 2);
3297 return false;
3299 else
3301 *total = -(COSTS_N_INSNS (GET_MODE_SIZE (mode)) / 2);
3302 return true;
3305 case IF_THEN_ELSE:
3306 *total = rtx_cost (XEXP (x, 0), code) + COSTS_N_INSNS (2);
3307 return true;
3309 case EQ:
3310 case NE:
3311 case LTU:
3312 case GTU:
3313 case LEU:
3314 case GEU:
3315 case LT:
3316 case GT:
3317 case LE:
3318 case GE:
3319 *total = 0;
3320 return false;
3322 default:
3323 *total = COSTS_N_INSNS (4);
3324 return true;
3328 /* Calculate the cost of a memory address. */
3330 static int
3331 ip2k_address_cost (rtx x)
3333 switch (legitimate_address_p (VOIDmode, x, 0))
3335 case 'S': /* Very low cost - (IP), (SP+N) or (DP+N) */
3336 return 8;
3338 case 'R': /* Indirected through IP. */
3339 return 8;
3341 case 'L': /* Label references. */
3342 return 0;
3344 case 'C': /* Constants and symbol references. */
3345 return 4;
3347 default:
3348 return 1000; /* Must reload. */
3352 /* As part of the machine-dependent reorg we look for opcode sequences where
3353 we do some operation and then move the results back to one of the original
3354 source operands. With working on the source operand directly is probably
3355 much cheaper and the move from this to the original source operand will be
3356 no more expensive than the original move. */
3358 #ifdef IP2K_MD_REORG_PASS
3359 static void
3360 mdr_resequence_xy_yx (first_insn)
3361 rtx first_insn;
3363 rtx insn;
3365 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3367 rtx set;
3369 if (GET_CODE (insn) != INSN)
3370 continue;
3372 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
3373 if (set == NULL_RTX)
3374 continue;
3376 /* Look for operations that tend to be very cheap to run when the source
3377 * and dest args are the same because the IP2022 has opcodes that can
3378 operate on the source directly. If we have to spill through the W
3379 register then we've possibly not got a good case for doing this. */
3380 if ((GET_CODE (XEXP (set, 0)) == REG
3381 || GET_CODE (XEXP (set, 0)) == MEM)
3382 && (GET_CODE (XEXP (set, 1)) == ASHIFT
3383 || GET_CODE (XEXP (set, 1)) == ASHIFTRT
3384 || GET_CODE (XEXP (set, 1)) == LSHIFTRT
3385 || GET_CODE (XEXP (set, 1)) == XOR
3386 || GET_CODE (XEXP (set, 1)) == IOR
3387 || GET_CODE (XEXP (set, 1)) == AND
3388 || GET_CODE (XEXP (set, 1)) == PLUS
3389 || GET_CODE (XEXP (set, 1)) == MINUS
3390 || GET_CODE (XEXP (set, 1)) == MULT))
3392 rtx set2;
3393 rtx next_insn;
3395 next_insn = next_nonnote_insn (insn);
3396 if (! next_insn)
3397 continue;
3399 if (GET_CODE (next_insn) != INSN)
3400 continue;
3402 set2 = ((GET_CODE (PATTERN (next_insn)) == SET)
3403 ? PATTERN (next_insn) : NULL_RTX);
3404 if (set2 == NULL_RTX)
3405 continue;
3407 if ((GET_CODE (XEXP (XEXP (set, 1), 0)) == REG
3408 || GET_CODE (XEXP (XEXP (set, 1), 0)) == MEM)
3409 && rtx_equal_p (XEXP (set2, 0), XEXP (XEXP (set, 1), 0))
3410 && rtx_equal_p (XEXP (set2, 1), XEXP (set, 0)))
3412 rtx next2_insn;
3413 rtx b_insn;
3415 b_insn = gen_rtx_SET (VOIDmode,
3416 XEXP (XEXP (set, 1), 0),
3417 gen_rtx_fmt_ee (GET_CODE (XEXP (set, 1)),
3418 GET_MODE (XEXP (set, 0)),
3419 XEXP (XEXP (set, 1), 0),
3420 XEXP (XEXP (set, 1), 1)));
3422 emit_insn_before (b_insn, insn);
3423 b_insn = gen_rtx_SET (GET_MODE (XEXP (set, 0)), XEXP (set, 0),
3424 XEXP (XEXP (set, 1), 0));
3425 next2_insn = emit_insn_before (b_insn, insn);
3426 delete_insn (insn);
3427 delete_insn (next_insn);
3428 insn = next2_insn;
3429 continue;
3432 /* Having tried with one operand of the expression, now, if
3433 appropriate, try to do the same thing with the second operand.
3434 Of course there are fewer operations that can match here
3435 because they must be commutative. */
3436 if (GET_RTX_CLASS (GET_CODE (XEXP (set, 1))) == RTX_COMM_ARITH
3437 && (GET_CODE (XEXP (XEXP (set, 1), 1)) == REG
3438 || GET_CODE (XEXP (XEXP (set, 1), 1)) == MEM)
3439 && rtx_equal_p (XEXP (set2, 0), XEXP (XEXP (set, 1), 1))
3440 && rtx_equal_p (XEXP (set2, 1), XEXP (set, 0)))
3442 rtx rtx_ee;
3443 rtx next2_insn;
3444 int swap_args;
3446 /* Try to ensure that we put things in a canonical form. */
3447 swap_args = (GET_CODE (XEXP (XEXP (set, 1), 0)) == REG
3448 || GET_CODE (XEXP (XEXP (set, 1), 0)) == MEM);
3449 rtx_ee = gen_rtx_fmt_ee (GET_CODE (XEXP (set, 1)),
3450 GET_MODE (XEXP (set, 0)),
3451 XEXP (XEXP (set, 1), swap_args ? 1 : 0),
3452 XEXP (XEXP (set, 1),
3453 swap_args ? 0 : 1));
3455 emit_insn_before (gen_rtx_SET (VOIDmode,
3456 XEXP (XEXP (set, 1), 1),
3457 rtx_ee),
3458 insn);
3459 next2_insn = emit_insn_before (gen_rtx_SET
3460 (GET_MODE (XEXP (set, 0)),
3461 XEXP (set, 0),
3462 XEXP (XEXP (set, 1), 1)),
3463 insn);
3464 delete_insn (insn);
3465 delete_insn (next_insn);
3466 insn = next2_insn;
3472 /* Replace and recurse until we've tried QImode pieces! */
3474 static void
3475 mdr_pres_replace_and_recurse (orig, with, insn)
3476 rtx orig;
3477 rtx with;
3478 rtx insn;
3480 enum machine_mode new_mode;
3482 validate_replace_rtx (orig, with, insn);
3484 switch (GET_MODE (orig))
3486 case DImode:
3487 case DFmode:
3488 new_mode = SImode;
3489 break;
3491 case SImode:
3492 case SFmode:
3493 new_mode = HImode;
3494 break;
3496 case HImode:
3497 new_mode = QImode;
3498 break;
3500 default:
3501 return;
3504 mdr_pres_replace_and_recurse (ip2k_get_low_half (orig, new_mode),
3505 ip2k_get_low_half (with, new_mode),
3506 insn);
3507 mdr_pres_replace_and_recurse (ip2k_get_high_half (orig, new_mode),
3508 ip2k_get_high_half (with, new_mode),
3509 insn);
3512 /* Assist the following function, mdr_propagate_reg_equivs(). */
3514 static void
3515 mdr_propagate_reg_equivs_sequence (first_insn, orig, equiv)
3516 rtx first_insn;
3517 rtx orig;
3518 rtx equiv;
3520 rtx try_insn;
3521 rtx try_equiv = equiv;
3523 /* First scan the RTL looking for anything else that might clobber what
3524 we're doing. If we find anything then we can't do the replacement. */
3525 for (try_insn = next_nonnote_insn (first_insn);
3526 try_insn; try_insn = next_nonnote_insn (try_insn))
3528 rtx pattern;
3530 if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
3531 continue;
3533 pattern = PATTERN (try_insn);
3534 if (GET_CODE (pattern) == PARALLEL)
3536 int j;
3538 for (j = 0; j < XVECLEN (pattern, 0); j++)
3540 rtx px = XVECEXP (pattern, 0, j);
3542 if (GET_CODE (px) == SET)
3543 if (! ip2k_composite_xexp_not_uses_reg_p (XEXP (px, 0),
3544 REGNO (orig),
3545 GET_MODE_SIZE (GET_MODE (orig))))
3546 return;
3549 else if (GET_CODE (pattern) == SET)
3551 if (! ip2k_composite_xexp_not_uses_reg_p (XEXP (pattern, 0),
3552 REGNO (orig),
3553 GET_MODE_SIZE (GET_MODE (orig))))
3554 return;
3558 /* Once we've decided that we're safe to do the replacement then make the
3559 changes. */
3560 for (try_insn = next_nonnote_insn (first_insn); try_insn;
3561 try_insn = next_nonnote_insn (try_insn))
3563 rtx set;
3564 rtx new_equiv = NULL_RTX;
3566 if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
3568 try_equiv = equiv;
3569 continue;
3572 set = ((GET_CODE (PATTERN (try_insn)) == SET)
3573 ? PATTERN (try_insn) : NULL_RTX);
3574 if (set == NULL_RTX)
3575 continue;
3577 /* We look for a special case of "push" operations screwing our
3578 register equivalence when it's based on a stack slot. We can
3579 track this one and replace the old equivalence expression with
3580 a new one. */
3581 if (GET_CODE (XEXP (set, 0)) == MEM
3582 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
3583 && REG_P (XEXP (XEXP (XEXP (set, 0), 0), 0))
3584 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP)
3586 /* XXX - need to ensure that we can track this without going
3587 out of range! */
3588 HOST_WIDE_INT disp = (INTVAL (XEXP (XEXP (try_equiv, 0), 1))
3589 + GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
3590 new_equiv = gen_rtx_MEM (GET_MODE (try_equiv),
3591 gen_rtx_PLUS (Pmode,
3592 gen_rtx_REG (HImode, REG_SP),
3593 GEN_INT (disp)));
3596 /* The replacement process is somewhat complicated by the fact that we
3597 might be dealing with what were originally subregs and thus we have
3598 to replace parts of our original expression! */
3599 mdr_pres_replace_and_recurse (orig, try_equiv, try_insn);
3601 if (new_equiv != NULL_RTX)
3602 try_equiv = new_equiv;
3606 /* Try propagating register equivalences forwards. It may be that we can
3607 replace a register use with an equivalent expression that already
3608 holds the same value and thus allow one or more register loads to
3609 be eliminated. */
3611 static void
3612 mdr_propagate_reg_equivs (first_insn)
3613 rtx first_insn;
3615 rtx insn;
3616 rtx set;
3618 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3620 if (GET_CODE (insn) != INSN)
3621 continue;
3623 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
3624 if (set == NULL_RTX)
3625 continue;
3627 /* Have we found a stack slot equivalence for a register? */
3628 if (REG_P (XEXP (set, 0))
3629 && REGNO (XEXP (set, 0)) >= 0x88
3630 && GET_CODE (XEXP (set, 1)) == MEM
3631 && GET_CODE (XEXP (XEXP (set, 1), 0)) == PLUS
3632 && REG_P (XEXP (XEXP (XEXP (set, 1), 0), 0))
3633 && REGNO (XEXP (XEXP (XEXP (set, 1), 0), 0)) == REG_SP
3634 && find_reg_note (insn, REG_EQUIV, NULL_RTX))
3636 mdr_propagate_reg_equivs_sequence (insn, XEXP (set, 0),
3637 XEXP (set, 1));
3642 /* Structure used to track jump targets. */
3644 struct dpre_jump_targets
3646 int target; /* Is this a jump target? */
3647 int reach_count; /* Number of ways we can reach this insn. */
3648 int touch_count; /* Number of times we've touched this
3649 insns during scanning. */
3650 rtx dp_equiv; /* DP-equivalence at this point. */
3653 struct dpre_jump_targets *ip2k_dpre_jump_targets;
3655 /* DP equivalence tracking used within DP reload elimination. */
3657 static int
3658 track_dp_reload (insn, dp_current, dp_current_ok, modifying)
3659 rtx insn;
3660 rtx *dp_current;
3661 int dp_current_ok;
3662 int modifying;
3664 rtx set;
3666 if (GET_CODE (insn) != INSN)
3668 *dp_current = NULL_RTX;
3669 return 1;
3672 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
3673 if (set == NULL_RTX)
3675 *dp_current = NULL_RTX;
3676 return 1;
3679 /* If we're pushing a PLUS or MINUS then it's a win if we can replace
3680 an expression for which DP is equivalent with DP. This happens
3681 surprisingly often when we pass a pointer to a structure embedded
3682 within another structure. */
3683 if (*dp_current != NULL_RTX
3684 && GET_CODE (XEXP (set, 0)) == MEM
3685 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
3686 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
3687 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
3688 && (GET_CODE (XEXP (set, 1)) == PLUS
3689 || GET_CODE (XEXP (set, 1)) == MINUS)
3690 && GET_CODE (*dp_current) != SYMBOL_REF
3691 && GET_CODE (*dp_current) != LABEL_REF
3692 && GET_CODE (*dp_current) != CONST)
3694 if (modifying)
3695 validate_replace_rtx (*dp_current, gen_rtx_REG (HImode, REG_DP), insn);
3698 /* Look for DP being modified. If it is, see if it's being changed
3699 to what it already is! */
3700 if (GET_CODE (XEXP (set, 0)) == REG
3701 && REGNO (XEXP (set, 0)) == REG_DP
3702 && GET_MODE (XEXP (set, 0)) == HImode)
3704 /* If this is an equivalence we can delete the new set operation. */
3705 if (*dp_current != NULL_RTX
3706 && rtx_equal_p (XEXP (set, 1), *dp_current))
3708 if (modifying)
3709 delete_insn (insn);
3711 else
3713 /* If we've not found an equivalence we can look for a special
3714 case where an operand of the expression that sets DP is
3715 already equivalent to DP and in that circumstance we simplify
3716 by replacing that expression with DP. */
3717 if (*dp_current != NULL_RTX
3718 && GET_CODE (*dp_current) != SYMBOL_REF
3719 && GET_CODE (*dp_current) != LABEL_REF
3720 && GET_CODE (*dp_current) != CONST
3721 && modifying)
3722 validate_replace_rtx (*dp_current, XEXP (set, 0), insn);
3724 /* Assuming that we're not loading DP from something that uses DP
3725 itself then we mark the new equivalence for DP. If we did match
3726 DP then we can't re-use this one. */
3727 if (ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_DP, 2))
3729 *dp_current = XEXP (set, 1);
3730 return 1;
3732 else
3734 *dp_current = NULL_RTX;
3735 return 1;
3739 else if (GET_CODE (XEXP (set, 0)) == REG
3740 && (REGNO (XEXP (set, 0)) == REG_DPL
3741 || REGNO (XEXP (set, 0)) == REG_DPH))
3743 /* If we clobber part of DP then we've clobbered any equivalences! */
3744 *dp_current = NULL_RTX;
3745 return 1;
3747 else if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2)
3748 && *dp_current != NULL_RTX
3749 && !ip2k_xexp_not_uses_reg_p (*dp_current, REG_SP, 2))
3751 /* We look for a special case of "push" operations screwing up the
3752 setting of DP when it's based on the stack. We can track this one
3753 and replace the old expression for DP with a new one. */
3754 if (GET_CODE (XEXP (set, 0)) == MEM
3755 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
3756 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
3757 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
3758 && GET_CODE (*dp_current) == MEM
3759 && GET_CODE (XEXP (*dp_current, 0)) == PLUS)
3761 /* XXX - need to ensure that we can track this without going
3762 out of range! */
3763 HOST_WIDE_INT disp = (INTVAL (XEXP (XEXP (*dp_current, 0), 1))
3764 + GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
3765 *dp_current = gen_rtx_MEM (HImode,
3766 gen_rtx_PLUS (Pmode,
3767 gen_rtx_REG (HImode, REG_SP),
3768 GEN_INT (disp)));
3769 return 1;
3772 /* Now we look for writes to the stack. We can determine if these will
3773 affect the equivalence we're tracking for DP and if not then we can
3774 keep tracking it. */
3775 if (GET_CODE (XEXP (set, 0)) == MEM
3776 && GET_CODE (*dp_current) == MEM)
3778 /* Look at the SP offsets and look for any overlaps. */
3779 int dp_cur_sp_offs = INTVAL (XEXP (XEXP (*dp_current, 0), 1));
3780 int set_sp_offs = INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1));
3782 if (abs (dp_cur_sp_offs - set_sp_offs) < 2)
3784 *dp_current = NULL_RTX;
3785 return 1;
3789 else if (GET_CODE (XEXP (set, 0)) == REG
3790 && *dp_current != NULL_RTX
3791 && !ip2k_xexp_not_uses_reg_p (*dp_current, REGNO (XEXP (set, 0)),
3792 GET_MODE_SIZE (GET_MODE (XEXP (set,
3793 0)))))
3795 /* If we've just clobbered all or part of a register reference that we
3796 were sharing for DP then we can't share it any more! */
3797 *dp_current = NULL_RTX;
3800 return dp_current_ok;
3803 /* As part of the machine-dependent reorg we scan loads and reloads of
3804 DP to see where any are redundant. This does happens because we
3805 are able to subsequently transform things in interesting ways. Sometimes
3806 gcc also does unnecessary reloads too so we try to eliminate these too. */
3808 static void
3809 mdr_try_dp_reload_elim (first_insn)
3810 rtx first_insn;
3812 rtx insn;
3813 struct dpre_jump_targets *djt;
3814 rtx dp_current;
3815 int incomplete_scan;
3816 int last_incomplete_scan;
3818 ip2k_dpre_jump_targets
3819 = (struct dpre_jump_targets *) xcalloc (get_max_uid (),
3820 sizeof (struct dpre_jump_targets));
3822 /* First we scan to build up a list of all CODE_LABEL insns and we work out
3823 how many different ways we can reach them. */
3824 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3826 if (GET_CODE (insn) == CODE_LABEL)
3828 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
3829 djt->target = 1;
3830 djt->reach_count = LABEL_NUSES (insn);
3831 djt->touch_count = 0;
3832 djt->dp_equiv = NULL_RTX;
3833 if (! prev_nonnote_insn (insn)
3834 || (prev_nonnote_insn (insn)
3835 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER))
3836 djt->reach_count++;
3840 /* Next we scan all of the ways of reaching the code labels to see
3841 what the DP register is equivalent to as we reach them. If we find
3842 that they're the same then we keep noting the matched value. We
3843 iterate around this until we reach a convergence on DP equivalences
3844 at all code labels - we have to be very careful not to be too
3845 optimistic! */
3846 incomplete_scan = -1;
3849 int dp_current_ok = 0;
3850 last_incomplete_scan = incomplete_scan;
3851 dp_current = NULL_RTX;
3853 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3855 /* If we have a code label then we need to see if we already know
3856 what the equivalence is at this point. If we do then we use it
3857 immediately, but if we don't then we have a special case to track
3858 when we hit a fallthrough-edge (label with no barrier preceding
3859 it). Any other accesses to the label must be from jump insns
3860 and so they're handled elsewhere. */
3861 if (GET_CODE (insn) == CODE_LABEL)
3863 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
3865 /* If we're fully characterized the use the equivalence. */
3866 if (djt->touch_count == djt->reach_count)
3868 dp_current = djt->dp_equiv;
3869 dp_current_ok = 1;
3870 continue;
3873 /* If we have a known equivalence for DP as we reach the
3874 fallthrough-edge then track this into the code label. */
3875 if (dp_current_ok
3876 && (! prev_nonnote_insn (insn)
3877 || (prev_nonnote_insn (insn)
3878 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER)))
3880 if (djt->touch_count == 0)
3881 djt->dp_equiv = dp_current;
3883 if (djt->touch_count < djt->reach_count)
3885 djt->touch_count++;
3886 if (! rtx_equal_p (djt->dp_equiv, dp_current))
3888 /* When we definitely know that we can't form an
3889 equivalence for DP here we must clobber anything
3890 that we'd started to track too. */
3891 djt->dp_equiv = NULL_RTX;
3892 dp_current = NULL_RTX;
3893 dp_current_ok = 1;
3898 /* If we've not completely characterized this code label then
3899 be cautious and assume that we don't know what DP is
3900 equivalent to. */
3901 if (djt->touch_count < djt->reach_count)
3903 dp_current = NULL_RTX;
3904 dp_current_ok = 0;
3907 continue;
3910 /* If we've hit a jump insn then we look for either an address
3911 vector (jump table) or for jump label references. */
3912 if (GET_CODE (insn) == JUMP_INSN)
3914 /* Don't attempt to track here if we don't have a known
3915 equivalence for DP at this point. */
3916 if (dp_current_ok)
3918 rtx pat = PATTERN (insn);
3919 if (GET_CODE (pat) == ADDR_VEC)
3921 int i;
3922 int len = XVECLEN (pat, 0);
3924 for (i = 0; i < len; i++)
3926 rtx vec_insn = XEXP (XVECEXP (pat, 0, i), 0);
3927 djt = &ip2k_dpre_jump_targets [INSN_UID (vec_insn)];
3929 if (djt->touch_count == 0)
3930 djt->dp_equiv = dp_current;
3932 if (djt->touch_count < djt->reach_count)
3934 djt->touch_count++;
3935 if (! rtx_equal_p (djt->dp_equiv, dp_current))
3936 djt->dp_equiv = NULL_RTX;
3940 else if (JUMP_LABEL (insn))
3942 rtx j_insn = JUMP_LABEL (insn);
3943 djt = &ip2k_dpre_jump_targets[INSN_UID (j_insn)];
3945 if (djt->touch_count == 0)
3946 djt->dp_equiv = dp_current;
3948 if (djt->touch_count < djt->reach_count)
3950 djt->touch_count++;
3951 if (! rtx_equal_p (djt->dp_equiv, dp_current))
3952 djt->dp_equiv = NULL_RTX;
3957 continue;
3960 /* Anything other than a code labal or jump arrives here.
3961 We try and track DP, but sometimes we might not be able to. */
3962 dp_current_ok = track_dp_reload (insn, &dp_current,
3963 dp_current_ok, 0);
3966 /* When we're looking to see if we've finished we count the number of
3967 paths through the code labels where we weren't able to definitively
3968 track DP.
3969 This number is used to see if we're converging on a solution.
3970 If this hits zero then we've fully converged, but if this stays the
3971 same as last time then we probably can't make any further
3972 progress. */
3973 incomplete_scan = 0;
3974 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3976 if (GET_CODE (insn) == CODE_LABEL)
3978 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
3979 if (djt->touch_count != djt->reach_count)
3981 incomplete_scan += (djt->reach_count - djt->touch_count);
3982 djt->dp_equiv = NULL_RTX;
3983 djt->touch_count = 0;
3988 while (incomplete_scan && incomplete_scan != last_incomplete_scan);
3990 /* Finally we scan the whole function and run DP elimination. When we hit
3991 a CODE_LABEL we pick up any stored equivalence since we now know that
3992 every path to this point entered with DP holding the same thing! If
3993 we subsequently have a reload that matches then we can eliminate it. */
3994 dp_current = NULL_RTX;
3995 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
3997 if (GET_CODE (insn) == JUMP_INSN)
3998 continue;
4000 if (GET_CODE (insn) == CODE_LABEL)
4002 djt = &ip2k_dpre_jump_targets[INSN_UID (insn)];
4003 dp_current = djt->dp_equiv;
4004 continue;
4007 track_dp_reload (insn, &dp_current, 1, 1);
4010 free (ip2k_dpre_jump_targets);
4013 /* As part of the machine-dependent reorg we look for reloads of DP
4014 that we can move to earlier points within the file.
4015 Moving these out of the way allows more peepholes to match. */
4017 static void
4018 mdr_try_move_dp_reload (first_insn)
4019 rtx first_insn;
4021 rtx insn;
4022 rtx set;
4023 rtx orig_first;
4025 /* Don't try to match the first instruction because we can't move it
4026 anyway. */
4027 orig_first = first_insn;
4028 first_insn = next_nonnote_insn (first_insn);
4030 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4032 if (GET_CODE (insn) != INSN)
4033 continue;
4035 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4036 if (set == NULL_RTX)
4037 continue;
4039 /* Look for DP being loaded. When we find this we start a rewind
4040 scan looking for possible positions to move this to. */
4041 if (GET_CODE (XEXP (set, 0)) == REG
4042 && REGNO (XEXP (set, 0)) == REG_DP
4043 && GET_MODE (XEXP (set, 0)) == HImode)
4045 int try_again;
4046 rtx try_insn = insn;
4050 rtx rewind;
4051 rtx check;
4053 try_again = 0;
4055 /* For now we do the *really* simple version of things and only
4056 attempt to move the load of DP if it's very safe to do so. */
4057 rewind = prev_nonnote_insn (try_insn);
4058 if (rewind != orig_first && rewind != NULL_RTX
4059 && GET_CODE (rewind) == INSN)
4061 check = ((GET_CODE (PATTERN (rewind)) == SET)
4062 ? PATTERN (rewind) : NULL_RTX);
4063 if (check != NULL_RTX
4064 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (check, 0))
4065 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (check, 1)))
4067 if (GET_CODE (XEXP (check, 0)) == REG
4068 && REGNO (XEXP (check, 0)) != REG_DPH
4069 && REGNO (XEXP (check, 0)) != REG_DPL
4070 && (ip2k_composite_xexp_not_uses_reg_p
4071 (XEXP (check, 1), REG_DP, 2))
4072 && (ip2k_composite_xexp_not_uses_reg_p
4073 (XEXP (set, 1),
4074 REGNO (XEXP (check, 0)),
4075 GET_MODE_SIZE (GET_MODE (XEXP (check, 0))))))
4077 emit_insn_before (set, rewind);
4078 if (try_insn == insn)
4079 insn = prev_nonnote_insn (insn);
4080 delete_insn (try_insn);
4081 try_insn = prev_nonnote_insn (rewind);
4082 try_again = 1;
4084 else if (GET_CODE (XEXP (set, 1)) == REG
4085 && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 1), REG_DP, 2)
4086 && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 0), REG_DP, 2)
4087 && ip2k_composite_xexp_not_uses_reg_p (XEXP (check, 0), REGNO (XEXP (set, 1)),
4088 GET_MODE_SIZE (GET_MODE (XEXP (set, 1)))))
4090 emit_insn_before (set, rewind);
4091 if (try_insn == insn)
4092 insn = prev_nonnote_insn (insn);
4093 delete_insn (try_insn);
4094 try_insn = prev_nonnote_insn (rewind);
4095 try_again = 1;
4100 while (try_again && try_insn);
4104 #endif /* IP2K_MD_REORG_PASS */
4106 /* Look to see if the expression, x, can have any stack references offset by
4107 a fixed constant, offset. If it definitely can then returns nonzero. */
4109 static int
4110 ip2k_check_can_adjust_stack_ref (rtx x, int offset)
4112 if (ARITHMETIC_P (x))
4113 return (ip2k_check_can_adjust_stack_ref (XEXP (x, 0), offset)
4114 && ip2k_check_can_adjust_stack_ref (XEXP (x, 1), offset));
4116 if (UNARY_P (x))
4117 return ip2k_check_can_adjust_stack_ref (XEXP (x, 0), offset);
4119 switch (GET_CODE (x))
4121 case REG:
4122 return (REGNO (x) != REG_SPH && REGNO (x) != REG_SPL);
4124 case MEM:
4125 if (GET_CODE (XEXP (x, 0)) != PLUS)
4126 return 1;
4128 if (GET_CODE (XEXP (XEXP (x, 0), 0)) != REG)
4129 return 1;
4131 if (REGNO (XEXP (XEXP (x, 0), 0)) != REG_SP)
4132 return 1;
4134 /* We can't allow this if the adjustment will create an
4135 invalid address. */
4136 return (INTVAL (XEXP (XEXP (x, 0), 1))
4137 + offset <= (128 - 2 * GET_MODE_SIZE (GET_MODE (x))));
4139 case CONST:
4140 case CONST_INT:
4141 case CONST_DOUBLE:
4142 case SYMBOL_REF:
4143 case LABEL_REF:
4144 return 1;
4146 default:
4147 return 0;
4151 /* Adjusts all of the stack references in the expression pointed to by x by
4152 a fixed offset. */
4154 static void
4155 ip2k_adjust_stack_ref (rtx *x, int offset)
4157 if (ARITHMETIC_P (*x))
4159 ip2k_adjust_stack_ref (&XEXP (*x, 0), offset);
4160 ip2k_adjust_stack_ref (&XEXP (*x, 1), offset);
4161 return;
4164 if (UNARY_P (*x))
4166 ip2k_adjust_stack_ref (&XEXP (*x, 0), offset);
4167 return;
4170 switch (GET_CODE (*x))
4172 case MEM:
4173 if (GET_CODE (XEXP (*x, 0)) != PLUS)
4174 return;
4176 if (GET_CODE (XEXP (XEXP (*x, 0), 0)) != REG)
4177 return;
4179 if (REGNO (XEXP (XEXP (*x, 0), 0)) != REG_SP)
4180 return;
4182 *x = copy_rtx (*x);
4183 XEXP (XEXP (*x, 0), 1) = GEN_INT (INTVAL (XEXP (XEXP (*x, 0), 1))
4184 + offset);
4185 break;
4187 default:
4188 break;
4192 #ifdef IP2K_MD_REORG_PASS
4193 /* As part of the machine-dependent reorg we look to move push instructions
4194 to earlier points within the file. Moving these out of the way allows more
4195 peepholes to match. */
4197 static void
4198 mdr_try_move_pushes (first_insn)
4199 rtx first_insn;
4201 rtx insn;
4202 rtx set;
4203 rtx orig_first;
4205 /* Don't try to match the first instruction because we can't move
4206 it anyway. */
4207 orig_first = first_insn;
4208 first_insn = next_nonnote_insn (first_insn);
4210 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4212 if (GET_CODE (insn) != INSN)
4213 continue;
4215 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4216 if (set == NULL_RTX)
4217 continue;
4219 /* Have we found a push instruction? */
4220 if (GET_CODE (XEXP (set, 0)) == MEM
4221 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
4222 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
4223 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
4224 && GET_CODE (XEXP (set, 1)) == REG)
4226 rtx try_insn = insn;
4227 unsigned int regno = REGNO (XEXP (set, 1));
4228 int reg_range = GET_MODE_SIZE (GET_MODE (XEXP (set, 1)));
4230 while (1)
4232 rtx rewind;
4233 rtx check;
4235 rewind = prev_nonnote_insn (try_insn);
4236 if (rewind == orig_first || rewind == NULL_RTX
4237 || GET_CODE (rewind) != INSN)
4238 break;
4240 check = (GET_CODE (PATTERN (rewind)) == SET) ? PATTERN (rewind) : NULL_RTX;
4241 if (check == NULL_RTX)
4242 break;
4244 if (! ip2k_check_can_adjust_stack_ref (XEXP (check, 0),
4245 reg_range)
4246 || ! ip2k_check_can_adjust_stack_ref (XEXP (check, 1),
4247 reg_range))
4248 break;
4250 /* If we've hit another push instruction we can't go any
4251 further. */
4252 if (GET_CODE (XEXP (check, 0)) == MEM
4253 && GET_CODE (XEXP (XEXP (check, 0), 0)) == POST_DEC
4254 && GET_CODE (XEXP (XEXP (XEXP (check, 0), 0), 0)) == REG
4255 && REGNO (XEXP (XEXP (XEXP (check, 0), 0), 0)) == REG_SP)
4256 break;
4258 /* If this is a register move then check that it doesn't clobber
4259 SP or any part of the instruction we're trying to move. */
4260 if (GET_CODE (XEXP (check, 0)) == REG)
4262 unsigned int check_reg = REGNO (XEXP (check, 0));
4263 int check_reg_range = GET_MODE_SIZE (GET_MODE (XEXP (check,
4264 0)));
4266 /* If we have a special case where what we want to push is
4267 being loaded by this "clobbering" insn then we can just
4268 push what is being used to load us and then do the load.
4269 This may seem a little odd, but we may subsequently be
4270 able to merge the load with another instruction as it
4271 may only be used once now! Note though that we
4272 specifically don't try this if the expression being
4273 loaded is an HImode MEM using IP. */
4274 if (check_reg == regno
4275 && check_reg_range == reg_range
4276 && ((GET_CODE (XEXP (check, 1)) == REG
4277 || (GET_CODE (XEXP (check, 1)) == MEM
4278 && (GET_MODE (XEXP (check, 1)) != HImode
4279 || ip2k_xexp_not_uses_reg_for_mem (XEXP (check, 1), REG_IP))))))
4281 switch (check_reg_range)
4283 case 1:
4284 emit_insn_before (gen_movqi (XEXP (set, 0),
4285 XEXP (check, 1)),
4286 rewind);
4287 delete_insn (try_insn);
4288 break;
4290 case 2:
4291 emit_insn_before (gen_movhi (XEXP (set, 0),
4292 XEXP (check, 1)),
4293 rewind);
4294 delete_insn (try_insn);
4295 break;
4297 case 4:
4298 emit_insn_before (gen_movsi (XEXP (set, 0),
4299 XEXP (check, 1)),
4300 rewind);
4301 delete_insn (try_insn);
4302 break;
4304 case 8:
4305 emit_insn_before (gen_movdi (XEXP (set, 0),
4306 XEXP (check, 1)),
4307 rewind);
4308 delete_insn (try_insn);
4309 break;
4312 ip2k_adjust_stack_ref (&XEXP (check, 0), reg_range);
4313 ip2k_adjust_stack_ref (&XEXP (check, 1), reg_range);
4314 try_insn = prev_nonnote_insn (rewind);
4315 /* XXX - should be a continue? */
4316 break;
4319 if ((check_reg == REG_SPL)
4320 || (check_reg == REG_SPH)
4321 || (((regno <= check_reg)
4322 && (regno + reg_range - 1) >= check_reg)
4323 || ((regno <= (check_reg + check_reg_range - 1))
4324 && ((regno + reg_range - 1)
4325 >= (check_reg + check_reg_range - 1)))))
4326 break;
4329 emit_insn_before (set, rewind);
4330 delete_insn (try_insn);
4331 ip2k_adjust_stack_ref (&XEXP (check, 0), reg_range);
4332 ip2k_adjust_stack_ref (&XEXP (check, 1), reg_range);
4333 try_insn = prev_nonnote_insn (rewind);
4339 /* Assist the following function, mdr_try_propagate_clr(). */
4341 static void
4342 mdr_try_propagate_clr_sequence (first_insn, regno)
4343 rtx first_insn;
4344 unsigned int regno;
4346 rtx try_insn;
4348 for (try_insn = next_nonnote_insn (first_insn); try_insn;
4349 try_insn = next_nonnote_insn (try_insn))
4351 rtx new_insn = NULL_RTX;
4352 rtx set2;
4354 if (GET_CODE (try_insn) == JUMP_INSN)
4355 continue;
4357 if (GET_CODE (try_insn) != INSN)
4358 break;
4360 set2 = ((GET_CODE (PATTERN (try_insn)) == SET)
4361 ? PATTERN (try_insn) : NULL_RTX);
4362 if (set2 == NULL_RTX)
4363 continue;
4365 if (GET_CODE (XEXP (set2, 1)) == AND
4366 && ((GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4367 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
4368 || (GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4369 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno)))
4371 rtx remove_insn = try_insn;
4372 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4373 const0_rtx), try_insn);
4374 delete_insn (remove_insn);
4376 else if (GET_CODE (XEXP (set2, 1)) == IOR
4377 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4378 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
4380 rtx remove_insn = try_insn;
4381 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4382 XEXP (XEXP (set2, 1), 1)),
4383 try_insn);
4384 delete_insn (remove_insn);
4386 else if (GET_CODE (XEXP (set2, 1)) == IOR
4387 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4388 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno)
4390 rtx remove_insn = try_insn;
4391 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4392 XEXP (XEXP (set2, 1), 0)),
4393 try_insn);
4394 delete_insn (remove_insn);
4396 else if (GET_CODE (XEXP (set2, 1)) == XOR
4397 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4398 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno)
4400 rtx remove_insn = try_insn;
4401 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4402 XEXP (XEXP (set2, 1), 1)),
4403 try_insn);
4404 delete_insn (remove_insn);
4406 else if (GET_CODE (XEXP (set2, 1)) == XOR
4407 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4408 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno)
4410 rtx remove_insn = try_insn;
4411 try_insn = emit_insn_before (gen_rtx_SET (QImode, XEXP (set2, 0),
4412 XEXP (XEXP (set2, 1), 0)),
4413 try_insn);
4414 delete_insn (remove_insn);
4417 if (GET_CODE (XEXP (set2, 0)) == REG)
4419 int reg2_range = GET_MODE_SIZE (GET_MODE (XEXP (set2, 0)));
4420 unsigned int regno2 = REGNO (XEXP (set2, 0));
4422 if (reg2_range == 1
4423 && regno == regno2
4424 && GET_CODE (XEXP (set2, 1)) == CONST_INT)
4426 int iv = INTVAL (XEXP (set2, 1));
4427 if (iv == 0xff)
4428 iv = -1;
4429 if (iv == 1 || iv == -1)
4431 new_insn = gen_rtx_SET (QImode, XEXP (set2, 0),
4432 gen_rtx_PLUS (QImode, XEXP (set2, 0),
4433 GEN_INT (iv)));
4434 new_insn = emit_insn_before (new_insn, try_insn);
4435 delete_insn (try_insn);
4436 try_insn = new_insn;
4438 break;
4441 if ((regno >= regno2) && (regno <= regno2 + reg2_range - 1))
4442 break;
4444 if (GET_CODE (XEXP (set2, 1)) == REG
4445 && REGNO (XEXP (set2, 1)) == regno)
4447 new_insn = emit_insn_before (gen_rtx_SET (QImode,
4448 XEXP (set2, 0),
4449 const0_rtx),
4450 try_insn);
4451 delete_insn (try_insn);
4452 try_insn = new_insn;
4456 if (GET_CODE (XEXP (set2, 0)) == CC0)
4458 if (GET_CODE (XEXP (set2, 1)) == REG
4459 && GET_MODE_SIZE (GET_MODE (XEXP (set2, 1))) == 2
4460 && REGNO (XEXP (set2, 1)) == regno)
4462 new_insn = gen_rtx_SET (VOIDmode, gen_rtx_CC0 (VOIDmode),
4463 gen_rtx_REG(QImode, regno + 1));
4464 new_insn = emit_insn_before (new_insn, try_insn);
4466 else if (GET_CODE (XEXP (set2, 1)) == COMPARE
4467 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4468 && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 0))) == 2
4469 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno
4470 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST_INT
4471 && INTVAL (XEXP (XEXP (set2, 1), 1)) >= 0
4472 && INTVAL (XEXP (XEXP (set2, 1), 1)) < 256)
4474 new_insn = gen_rtx_SET (VOIDmode, cc0_rtx,
4475 gen_rtx_COMPARE(QImode,
4476 gen_rtx_REG (QImode,
4477 regno + 1),
4478 XEXP (XEXP (set2, 1),
4479 1)));
4480 new_insn = emit_insn_before (new_insn, try_insn);
4483 /* If we have inserted a replacement for a CC0 setter operation
4484 then we need to delete the old one. */
4485 if (new_insn != NULL_RTX)
4487 delete_insn (try_insn);
4488 try_insn = new_insn;
4490 /* Now as we know that we have just done an unsigned compare
4491 (remember we were zero-extended by the clr!) we also know
4492 that we don't need a signed jump insn. If we find that
4493 our next isns is a signed jump then make it unsigned! */
4494 if (GET_CODE (next_nonnote_insn (try_insn)) == JUMP_INSN)
4496 rtx set3;
4498 try_insn = next_nonnote_insn (try_insn);
4499 set3 = ((GET_CODE (PATTERN (try_insn)) == SET)
4500 ? PATTERN (try_insn) : NULL_RTX);
4501 if (set3 == NULL_RTX)
4502 continue;
4504 /* If we discover that our jump target is only accessible
4505 from here then we can continue our "clr" propagation to
4506 it too! */
4507 if (LABEL_NUSES (JUMP_LABEL (try_insn)) == 1)
4508 mdr_try_propagate_clr_sequence (JUMP_LABEL (try_insn),
4509 regno);
4511 if (GET_CODE (XEXP (set3, 0)) == PC
4512 && GET_CODE (XEXP (set3, 1)) == IF_THEN_ELSE
4513 && (GET_CODE (XEXP (XEXP (set3, 1), 0)) == GT
4514 || GET_CODE (XEXP (XEXP (set3, 1), 0)) == GE
4515 || GET_CODE (XEXP (XEXP (set3, 1), 0)) == LT
4516 || GET_CODE (XEXP (XEXP (set3, 1), 0)) == LE)
4517 && GET_CODE (XEXP (XEXP (XEXP (set3, 1), 0), 0)) == CC0
4518 && (GET_CODE (XEXP (XEXP (XEXP (set3, 1), 0), 1))
4519 == CONST_INT)
4520 && GET_CODE (XEXP (XEXP (set3, 1), 1)) == LABEL_REF
4521 && GET_CODE (XEXP (XEXP (set3, 1), 2)) == PC)
4523 enum rtx_code code;
4524 rtx new_if;
4525 rtx cmp;
4527 /* Replace our old conditional jump with a new one that
4528 does the unsigned form of what was previously a
4529 signed comparison. */
4530 code = GET_CODE (XEXP (XEXP (set3, 1), 0));
4531 cmp = gen_rtx_fmt_ee ((code == GT
4532 ? GTU
4533 : (code == GE
4534 ? GEU
4535 : (code == LT ? LTU : LEU))),
4536 VOIDmode,
4537 XEXP (XEXP (XEXP (set3, 1), 0), 0),
4538 XEXP (XEXP (XEXP (set3, 1), 0),
4539 1));
4540 new_if
4541 = gen_rtx_SET (GET_MODE (set3),
4542 pc_rtx,
4543 gen_rtx_IF_THEN_ELSE
4544 (GET_MODE (XEXP (set3, 1)), cmp,
4545 XEXP (XEXP (set3, 1), 1),
4546 XEXP (XEXP (set3, 1), 2)));
4547 new_insn = emit_jump_insn_before (new_if, try_insn);
4548 LABEL_NUSES (JUMP_LABEL (try_insn))++;
4549 delete_insn (try_insn);
4550 try_insn = new_insn;
4555 else if (GET_CODE (XEXP (set2, 1)) == PLUS
4556 && GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4557 && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 0))) == 2
4558 && REGNO (XEXP (XEXP (set2, 1), 0)) == regno
4559 && (GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4560 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == MEM
4561 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST_INT
4562 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == CONST
4563 || GET_CODE (XEXP (XEXP (set2, 1), 1)) == SYMBOL_REF))
4565 rtx extend = gen_rtx_ZERO_EXTEND (HImode,
4566 gen_rtx_REG (QImode, regno + 1));
4567 new_insn = gen_rtx_SET (HImode, XEXP (set2, 0),
4568 gen_rtx_PLUS (HImode, extend,
4569 XEXP (XEXP (set2, 1), 1)));
4570 new_insn = emit_insn_before (new_insn, try_insn);
4571 delete_insn (try_insn);
4572 try_insn = new_insn;
4574 else if (GET_CODE (XEXP (set2, 1)) == PLUS
4575 && GET_CODE (XEXP (XEXP (set2, 1), 1)) == REG
4576 && GET_MODE_SIZE (GET_MODE (XEXP (XEXP (set2, 1), 1))) == 2
4577 && REGNO (XEXP (XEXP (set2, 1), 1)) == regno
4578 && (GET_CODE (XEXP (XEXP (set2, 1), 0)) == REG
4579 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == MEM
4580 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == CONST_INT
4581 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == CONST
4582 || GET_CODE (XEXP (XEXP (set2, 1), 0)) == SYMBOL_REF))
4584 rtx t_src = gen_rtx_PLUS (HImode,
4585 gen_rtx_ZERO_EXTEND (HImode,
4586 gen_rtx_REG (QImode,
4587 regno
4588 + 1)),
4589 XEXP (XEXP (set2, 1), 0));
4590 new_insn = emit_insn_before (gen_rtx_SET (HImode, XEXP (set2, 0),
4591 t_src),
4592 try_insn);
4593 delete_insn (try_insn);
4594 try_insn = new_insn;
4599 /* One of the things that can quite often happen with an 8-bit CPU is that
4600 we end up clearing the MSByte of a 16-bit value. Unfortunately, all too
4601 often gcc doesn't have any way to realize that only half of the value is
4602 useful and ends up doing more work than it should. We scan for such
4603 occurrences here, track them and reduce compare operations to a smaller
4604 size where possible.
4606 Note that this is somewhat different to move propagation as we may
4607 actually change some instruction patterns when we're doing this whereas
4608 move propagation is just about doing a search and replace. */
4610 static void
4611 mdr_try_propagate_clr (first_insn)
4612 rtx first_insn;
4614 rtx insn;
4615 rtx set;
4617 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4619 if (GET_CODE (insn) != INSN)
4620 continue;
4622 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4623 if (set == NULL_RTX)
4624 continue;
4626 /* Have we found a "clr" instruction? */
4627 if (GET_CODE (XEXP (set, 0)) == REG
4628 && GET_CODE (XEXP (set, 1)) == CONST_INT
4629 && GET_MODE_SIZE (GET_MODE (XEXP (set, 0))) == 1
4630 && INTVAL (XEXP (set, 1)) == 0)
4632 mdr_try_propagate_clr_sequence (insn, REGNO (XEXP (set, 0)));
4636 #endif /* IP2K_MD_REORG_PASS */
4638 /* Look to see if the expression, x, does not make any memory references
4639 via the specified register. This is very conservative and only returns
4640 nonzero if we definitely don't have such a memory ref. */
4642 static int
4643 ip2k_xexp_not_uses_reg_for_mem (rtx x, unsigned int regno)
4645 if (regno & 1)
4646 regno &= 0xfffffffe;
4648 switch (GET_CODE (x))
4650 case REG:
4651 return 1;
4653 case MEM:
4654 if ((GET_CODE (XEXP (x, 0)) == PLUS
4655 && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
4656 && REGNO (XEXP (XEXP (x, 0), 0)) == regno)
4657 || (GET_CODE (XEXP (x, 0)) == REG
4658 && REGNO (XEXP (x, 0)) == regno))
4659 return 0;
4660 else
4661 return 1;
4663 case CONST:
4664 case CONST_INT:
4665 case CONST_DOUBLE:
4666 case SYMBOL_REF:
4667 case LABEL_REF:
4668 case CC0:
4669 case PC:
4670 return 1;
4672 default:
4673 if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS)
4674 return (ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno)
4675 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 1), regno)
4676 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 2), regno));
4678 if (BINARY_P (x))
4679 return (ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno)
4680 && ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 1), regno));
4682 if (UNARY_P (x)
4683 || GET_RTX_CLASS (GET_CODE (x)) == '3')
4684 return ip2k_xexp_not_uses_reg_for_mem (XEXP (x, 0), regno);
4686 return 0;
4690 #ifdef IP2K_MD_REORG_PASS
4691 /* Assist the following function, mdr_try_propagate_move(). */
4693 static void
4694 mdr_try_propagate_move_sequence (first_insn, orig, equiv)
4695 rtx first_insn;
4696 rtx orig;
4697 rtx equiv;
4699 rtx try_insn;
4701 for (try_insn = next_nonnote_insn (first_insn); try_insn;
4702 try_insn = next_nonnote_insn (try_insn))
4704 rtx set;
4705 int range;
4706 rtx new_equiv = NULL_RTX;
4708 if (GET_CODE (try_insn) != JUMP_INSN && GET_CODE (try_insn) != INSN)
4709 break;
4711 set = single_set (try_insn);
4712 if (set == NULL_RTX)
4713 break;
4715 range = MAX (GET_MODE_SIZE (GET_MODE (equiv)),
4716 GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
4718 if (GET_CODE (equiv) == REG
4719 && REGNO (equiv) == REG_W
4720 && (recog_memoized (try_insn) < 0
4721 || get_attr_clobberw (try_insn) != CLOBBERW_NO)
4722 && (! (GET_CODE (XEXP (set, 0)) == REG
4723 && REGNO (XEXP (set, 0)) == REG_W
4724 && rtx_equal_p (XEXP (set, 1), orig))))
4725 break;
4726 else if (GET_CODE (XEXP (set, 0)) == REG
4727 && (REGNO (XEXP (set, 0)) == REG_SP
4728 || ! ip2k_xexp_not_uses_reg_p (equiv, REGNO (XEXP (set, 0)),
4729 range)
4730 || ! ip2k_xexp_not_uses_reg_p (orig, REGNO (XEXP (set, 0)),
4731 range))
4732 && ! rtx_equal_p (equiv, XEXP (set, 0))
4733 && ! rtx_equal_p (orig, XEXP (set, 0)))
4734 break;
4735 else if (GET_CODE (orig) == REG
4736 && (REGNO (orig) == REG_IPL
4737 || REGNO (orig) == REG_IPH
4738 || REGNO (orig) == REG_DPL
4739 || REGNO (orig) == REG_DPH)
4740 && (! ip2k_xexp_not_uses_reg_for_mem (XEXP (set, 0),
4741 REGNO (orig))
4742 || ! ip2k_xexp_not_uses_reg_for_mem (XEXP (set, 1),
4743 REGNO (orig))))
4744 break;
4745 else if (GET_CODE (XEXP (set, 0)) == MEM
4746 && GET_CODE (equiv) == MEM)
4748 if (! ip2k_xexp_not_uses_reg_p (equiv, REG_SP, 2))
4750 if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2))
4752 /* We look for a special case of "push" operations screwing
4753 our register equivalence when it's based on a stack slot.
4754 We can track this one and replace the old equivalence
4755 expression with a new one. */
4756 if (GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
4757 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
4758 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
4759 && GET_CODE (XEXP (equiv, 0)) == PLUS
4760 && REGNO (XEXP (XEXP (equiv, 0), 0)) == REG_SP)
4762 int md_size = GET_MODE_SIZE (GET_MODE (XEXP (set, 0)));
4763 int new_sp_offs = INTVAL (XEXP (XEXP (equiv, 0), 1))
4764 + md_size;
4766 /* Don't allow an invalid stack pointer offset to be
4767 created. */
4768 if (new_sp_offs > (128 - 2 * md_size))
4769 break;
4771 new_equiv
4772 = gen_rtx_MEM (GET_MODE (equiv),
4773 gen_rtx_PLUS (Pmode,
4774 gen_rtx_REG (HImode ,
4775 REG_SP),
4776 GEN_INT (new_sp_offs)));
4778 else if (! rtx_equal_p (equiv, XEXP (set, 0)))
4780 /* Look at the SP offsets and look for any overlaps. */
4781 int equiv_offs = GET_CODE (XEXP (equiv, 0)) == PLUS
4782 ? INTVAL (XEXP (XEXP (equiv, 0), 1))
4783 : 0;
4784 int set_offs
4785 = (GET_CODE (XEXP (XEXP (set, 0), 0)) == PLUS
4786 ? INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1))
4787 : 0);
4789 if (abs (equiv_offs - set_offs) < range)
4790 break;
4795 if (! ip2k_xexp_not_uses_reg_p (equiv, REG_IP, 2))
4796 break;
4798 if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_DP, 2)
4799 && ! ip2k_xexp_not_uses_reg_p (equiv, REG_DP, 2)
4800 && ! rtx_equal_p (equiv, XEXP (set, 0)))
4802 /* Look at the DP offsets and look for any overlaps. */
4803 int equiv_offs = GET_CODE (XEXP (equiv, 0)) == PLUS
4804 ? INTVAL (XEXP (XEXP (equiv, 0), 1))
4805 : 0;
4806 int set_offs = GET_CODE (XEXP (XEXP (set, 0), 0)) == PLUS
4807 ? INTVAL (XEXP (XEXP (XEXP (set, 0), 0), 1))
4808 : 0;
4810 if (abs (equiv_offs - set_offs) < range)
4811 break;
4815 validate_replace_rtx_subexp (orig, equiv, try_insn, &XEXP (set, 1));
4817 if (rtx_equal_p (equiv, XEXP (set, 0))
4818 || rtx_equal_p (orig, XEXP (set, 0)))
4819 break;
4821 if (new_equiv != NULL_RTX)
4822 equiv = new_equiv;
4826 /* Try propagating move instructions forwards. It may be that we can
4827 replace a register use with an equivalent expression that already
4828 holds the same value and thus allow one or more register loads to
4829 be eliminated. */
4831 static void
4832 mdr_try_propagate_move (first_insn)
4833 rtx first_insn;
4835 rtx insn;
4836 rtx set;
4838 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4840 if (GET_CODE (insn) != INSN)
4841 continue;
4843 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4844 if (set == NULL_RTX)
4845 continue;
4847 /* Have we found a simple move instruction? */
4848 if (GET_CODE (XEXP (set, 0)) == REG
4849 && (REGNO (XEXP (set, 0)) >= 0x80
4850 || REGNO (XEXP (set, 0)) == REG_DPL
4851 || REGNO (XEXP (set, 0)) == REG_DPH
4852 || REGNO (XEXP (set, 0)) == REG_IPL
4853 || REGNO (XEXP (set, 0)) == REG_IPH)
4854 && ((GET_CODE (XEXP (set, 1)) == REG
4855 && REGNO (XEXP (set, 1)) != REG_SP
4856 && ip2k_xexp_not_uses_reg_p (XEXP (set, 0),
4857 REGNO (XEXP (set, 1)),
4858 GET_MODE_SIZE (GET_MODE (XEXP (set,
4859 0)))))
4860 || (GET_CODE (XEXP (set, 1)) == MEM
4861 && (ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_IP, 2)
4862 || GET_MODE (XEXP (set, 1)) == QImode)
4863 && ((REGNO (XEXP (set, 0)) != REG_DPH
4864 && REGNO (XEXP (set, 0)) != REG_DPL)
4865 || ip2k_xexp_not_uses_reg_p (XEXP (set, 1), REG_DP, 2)))
4866 || (GET_CODE (XEXP (set, 1)) == CONST_INT
4867 && (GET_MODE (XEXP (set, 0)) != QImode
4868 || INTVAL (XEXP (set, 1)) != 0))
4869 || GET_CODE (XEXP (set, 1)) == CONST_DOUBLE
4870 || GET_CODE (XEXP (set, 1)) == CONST
4871 || GET_CODE (XEXP (set, 1)) == SYMBOL_REF))
4873 mdr_try_propagate_move_sequence (insn, XEXP (set, 0), XEXP (set, 1));
4878 /* Try to remove redundant instructions. */
4880 static void
4881 mdr_try_remove_redundant_insns (first_insn)
4882 rtx first_insn;
4884 rtx insn;
4886 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
4888 rtx set;
4889 enum machine_mode mode;
4890 int md_size;
4891 HOST_WIDE_INT pattern;
4892 int i;
4894 if (GET_CODE (insn) != INSN)
4895 continue;
4897 if (GET_CODE (PATTERN (insn)) == CONST_INT)
4899 /* We've found a dummy expression. */
4900 rtx remove_insn = insn;
4901 insn = prev_nonnote_insn (insn);
4902 delete_insn (remove_insn);
4903 continue;
4906 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4907 if (set == NULL_RTX)
4908 continue;
4910 mode = GET_MODE (XEXP (set, 0));
4911 md_size = GET_MODE_SIZE (mode);
4912 if ((md_size < 1) || (md_size > 4))
4913 continue;
4915 pattern = 0;
4916 for (i = 0; i < md_size; i++)
4918 pattern <<= 8;
4919 pattern |= 0xff;
4922 if ((GET_CODE (XEXP (set, 1)) == AND
4923 && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
4924 && INTVAL (XEXP (XEXP (set, 1), 1)) == pattern)
4925 || ((GET_CODE (XEXP (set, 1)) == IOR
4926 || GET_CODE (XEXP (set, 1)) == XOR)
4927 && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
4928 && INTVAL (XEXP (XEXP (set, 1), 1)) == 0x00))
4930 /* We've found an AND with all 1's, an XOR with all 0's or an
4931 IOR with 0's. */
4932 rtx remove_insn = insn;
4934 /* Is it completely redundant or should it become a move insn? */
4935 if (! rtx_equal_p (XEXP (set, 0), XEXP (XEXP (set, 1), 0)))
4937 emit_insn_before (gen_rtx_SET (mode,
4938 XEXP (set, 0),
4939 XEXP (XEXP (set, 1), 0)),
4940 insn);
4943 insn = prev_nonnote_insn(insn);
4944 delete_insn (remove_insn);
4946 else if (GET_CODE (XEXP (set, 1)) == AND
4947 && GET_CODE (XEXP (XEXP (set, 1), 1)) == CONST_INT
4948 && INTVAL (XEXP (XEXP (set, 1), 1)) == 0)
4950 /* We've found an AND with all 0's. */
4951 rtx remove_insn = insn;
4952 insn = emit_insn_before (gen_rtx_SET (mode,
4953 XEXP (set, 0),
4954 XEXP (XEXP (set, 1), 1)),
4955 insn);
4956 delete_insn (remove_insn);
4961 /* Structure used to track jump targets. */
4963 struct we_jump_targets
4965 int target; /* Is this a jump target? */
4966 int reach_count; /* Number of ways we can reach this insn. */
4967 int touch_count; /* Number of times we've touched this insn
4968 during scanning. */
4969 rtx w_equiv; /* WREG-equivalence at this point. */
4972 struct we_jump_targets *ip2k_we_jump_targets;
4974 /* WREG equivalence tracking used within DP reload elimination. */
4976 static int
4977 track_w_reload (insn, w_current, w_current_ok, modifying)
4978 rtx insn;
4979 rtx *w_current;
4980 int w_current_ok;
4981 int modifying;
4983 rtx set;
4985 if (GET_CODE (insn) != INSN)
4987 *w_current = NULL_RTX;
4988 return 1;
4991 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
4992 if (set == NULL_RTX)
4994 *w_current = NULL_RTX;
4995 return 1;
4998 /* Look for W being modified. If it is, see if it's being changed
4999 to what it already is! */
5000 if (GET_CODE (XEXP (set, 0)) == REG
5001 && REGNO (XEXP (set, 0)) == REG_W
5002 && GET_MODE (XEXP (set, 0)) == QImode)
5004 /* If this is an equivalence we can delete the new set operation. */
5005 if (*w_current != NULL_RTX
5006 && rtx_equal_p (XEXP (set, 1), *w_current))
5008 if (modifying)
5009 delete_insn (insn);
5011 else
5013 *w_current = XEXP (set, 1);
5014 return 1;
5017 else if (recog_memoized (insn) < 0
5018 || get_attr_clobberw (insn) != CLOBBERW_NO)
5020 /* If we clobber W then we've clobbered any equivalences ! */
5021 *w_current = NULL_RTX;
5022 return 1;
5024 else if (! ip2k_xexp_not_uses_reg_p (XEXP (set, 0), REG_SP, 2)
5025 && *w_current != NULL_RTX
5026 && !ip2k_xexp_not_uses_reg_p (*w_current, REG_SP, 2))
5028 /* We look for a special case of "push" operations screwing up the
5029 setting of DP when it's based on the stack. We can track this one
5030 and replace the old expression for DP with a new one. */
5031 if (GET_CODE (XEXP (set, 0)) == MEM
5032 && GET_CODE (XEXP (XEXP (set, 0), 0)) == POST_DEC
5033 && GET_CODE (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG
5034 && REGNO (XEXP (XEXP (XEXP (set, 0), 0), 0)) == REG_SP
5035 && GET_CODE (*w_current) == MEM
5036 && GET_CODE (XEXP (*w_current, 0)) == PLUS)
5038 /* XXX - need to ensure that we can track this without going
5039 out of range! */
5040 rtx val = GEN_INT (INTVAL (XEXP (XEXP (*w_current, 0), 1))
5041 + GET_MODE_SIZE (GET_MODE (XEXP (set, 0))));
5042 *w_current
5043 = gen_rtx_MEM (HImode, gen_rtx_PLUS (Pmode,
5044 gen_rtx_REG(HImode, REG_SP),
5045 val));
5046 return 1;
5049 else if (GET_CODE (XEXP (set, 0)) == REG
5050 && *w_current != NULL_RTX
5051 && !ip2k_xexp_not_uses_reg_p (*w_current, REGNO (XEXP (set, 0)),
5052 GET_MODE_SIZE (GET_MODE (XEXP (set
5053 , 0)))))
5055 /* If we've just clobbered all or part of a register reference that we
5056 were sharing for W then we can't share it any more! */
5057 *w_current = NULL_RTX;
5060 return w_current_ok;
5063 /* As part of the machine-dependent reorg we scan moves into w and track them
5064 to see where any are redundant. */
5066 static void
5067 mdr_try_wreg_elim (first_insn)
5068 rtx first_insn;
5070 rtx insn;
5071 struct we_jump_targets *wjt;
5072 rtx w_current;
5073 int incomplete_scan;
5074 int last_incomplete_scan;
5076 ip2k_we_jump_targets
5077 = (struct we_jump_targets *) xcalloc (get_max_uid (),
5078 sizeof (struct we_jump_targets));
5080 /* First we scan to build up a list of all CODE_LABEL insns and we work out
5081 how many different ways we can reach them. */
5082 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5084 if (GET_CODE (insn) == CODE_LABEL)
5086 wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5087 wjt->target = 1;
5088 wjt->reach_count = LABEL_NUSES (insn);
5089 wjt->touch_count = 0;
5090 wjt->w_equiv = NULL_RTX;
5091 if (! prev_nonnote_insn (insn)
5092 || (prev_nonnote_insn (insn)
5093 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER))
5094 wjt->reach_count++;
5098 /* Next we scan all of the ways of reaching the code labels to see
5099 what the WREG register is equivalent to as we reach them. If we find
5100 that they're the same then we keep noting the matched value. We
5101 iterate around this until we reach a convergence on WREG equivalences
5102 at all code labels - we have to be very careful not to be too
5103 optimistic! */
5104 incomplete_scan = -1;
5107 int w_current_ok = 0;
5108 last_incomplete_scan = incomplete_scan;
5109 w_current = NULL_RTX;
5111 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5113 /* If we have a code label then we need to see if we already know
5114 what the equivalence is at this point. If we do then we use it
5115 immediately, but if we don't then we have a special case to track
5116 when we hit a fallthrough-edge (label with no barrier preceding
5117 it). Any other accesses to the label must be from jump insns
5118 and so they're handled elsewhere. */
5119 if (GET_CODE (insn) == CODE_LABEL)
5121 wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5123 /* If we're fully characterized the use the equivalence. */
5124 if (wjt->touch_count == wjt->reach_count)
5126 w_current = wjt->w_equiv;
5127 w_current_ok = 1;
5128 continue;
5131 /* If we have a known equivalence for WREG as we reach the
5132 fallthrough-edge then track this into the code label. */
5133 if (w_current_ok
5134 && (! prev_nonnote_insn (insn)
5135 || (prev_nonnote_insn (insn)
5136 && GET_CODE (prev_nonnote_insn (insn)) != BARRIER)))
5138 if (wjt->touch_count == 0)
5139 wjt->w_equiv = w_current;
5141 if (wjt->touch_count < wjt->reach_count)
5143 wjt->touch_count++;
5144 if (! rtx_equal_p (wjt->w_equiv, w_current))
5146 /* When we definitely know that we can't form an
5147 equivalence for WREG here we must clobber anything
5148 that we'd started to track too. */
5149 wjt->w_equiv = NULL_RTX;
5150 w_current = NULL_RTX;
5151 w_current_ok = 1;
5156 /* If we've not completely characterized this code label then
5157 be cautious and assume that we don't know what WREG is
5158 equivalent to. */
5159 if (wjt->touch_count < wjt->reach_count)
5161 w_current = NULL_RTX;
5162 w_current_ok = 0;
5165 continue;
5168 /* If we've hit a jump insn then we look for either an address
5169 vector (jump table) or for jump label references. */
5170 if (GET_CODE (insn) == JUMP_INSN)
5172 /* Don't attempt to track here if we don't have a known
5173 equivalence for WREG at this point. */
5174 if (w_current_ok)
5176 if (JUMP_LABEL (insn))
5179 = &ip2k_we_jump_targets[INSN_UID (JUMP_LABEL (insn))];
5181 if (wjt->touch_count == 0)
5182 wjt->w_equiv = w_current;
5184 if (wjt->touch_count < wjt->reach_count)
5186 wjt->touch_count++;
5187 if (! rtx_equal_p (wjt->w_equiv, w_current))
5188 wjt->w_equiv = NULL_RTX;
5193 continue;
5196 /* Anything other than a code labal or jump arrives here. We try and
5197 track WREG, but sometimes we might not be able to. */
5198 w_current_ok = track_w_reload (insn, &w_current, w_current_ok, 0);
5201 /* When we're looking to see if we've finished we count the number of
5202 paths through the code labels where we weren't able to definitively
5203 track WREG. This number is used to see if we're converging on a
5204 solution.
5205 If this hits zero then we've fully converged, but if this stays the
5206 same as last time then we probably can't make any further
5207 progress. */
5208 incomplete_scan = 0;
5209 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5211 if (GET_CODE (insn) == CODE_LABEL)
5213 wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5214 if (wjt->touch_count != wjt->reach_count)
5216 incomplete_scan += (wjt->reach_count - wjt->touch_count);
5217 wjt->w_equiv = NULL_RTX;
5218 wjt->touch_count = 0;
5223 while (incomplete_scan && incomplete_scan != last_incomplete_scan);
5225 /* Finally we scan the whole function and run WREG elimination. When we hit
5226 a CODE_LABEL we pick up any stored equivalence since we now know that
5227 every path to this point entered with WREG holding the same thing! If
5228 we subsequently have a reload that matches then we can eliminate it. */
5229 w_current = NULL_RTX;
5230 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5232 if (GET_CODE (insn) == JUMP_INSN)
5233 continue;
5235 if (GET_CODE (insn) == CODE_LABEL)
5237 wjt = &ip2k_we_jump_targets[INSN_UID (insn)];
5238 w_current = wjt->w_equiv;
5239 continue;
5242 track_w_reload (insn, &w_current, 1, 1);
5245 free (ip2k_we_jump_targets);
5247 #endif /* IP2K_MD_REORG_PASS */
5249 /* We perform a lot of untangling of the RTL within the reorg pass since
5250 the IP2k requires some really bizarre (and really undesirable) things
5251 to happen in order to guarantee not aborting. This pass causes several
5252 earlier passes to be re-run as it progressively transforms things,
5253 making the subsequent runs continue to win. */
5255 static void
5256 ip2k_reorg (void)
5258 #ifdef IP2K_MD_REORG_PASS
5259 rtx first_insn, insn, set;
5260 #endif
5262 CC_STATUS_INIT;
5264 if (optimize == 0)
5266 ip2k_reorg_completed = 1;
5267 ip2k_reorg_split_dimode = 1;
5268 ip2k_reorg_split_simode = 1;
5269 ip2k_reorg_split_himode = 1;
5270 ip2k_reorg_split_qimode = 1;
5271 ip2k_reorg_merge_qimode = 1;
5272 return;
5274 #ifndef IP2K_MD_REORG_PASS
5275 ip2k_reorg_completed = 1;
5276 ip2k_reorg_split_dimode = 1;
5277 ip2k_reorg_split_simode = 1;
5278 ip2k_reorg_split_himode = 1;
5279 ip2k_reorg_split_qimode = 1;
5280 ip2k_reorg_merge_qimode = 1;
5281 #else
5282 /* All optimizations below must be debugged and enabled one by one.
5283 All of them commented now because of abort in GCC core. */
5285 ip2k_reorg_in_progress = 1;
5287 first_insn = get_insns ();
5289 /* Look for size effects of earlier optimizations - in particular look for
5290 situations where we're saying "use" a register on one hand but immediately
5291 tagging it as "REG_DEAD" at the same time! Seems like a bug in core-gcc
5292 somewhere really but this is what we have to live with! */
5293 for (insn = first_insn; insn; insn = NEXT_INSN (insn))
5295 rtx body;
5297 if (GET_CODE (insn) == CODE_LABEL
5298 || GET_CODE (insn) == NOTE
5299 || GET_CODE (insn) == BARRIER)
5300 continue;
5302 if (!INSN_P (insn))
5303 continue;
5305 body = PATTERN (insn);
5306 if (GET_CODE (body) == USE)
5307 if (GET_CODE (XEXP (body, 0)) == REG)
5309 int reg;
5311 reg = REGNO (XEXP (body, 0));
5312 if (find_regno_note (insn, REG_DEAD, reg))
5314 delete_insn (insn);
5319 /* There's a good chance that since we last did CSE that we've rearranged
5320 things in such a way that another go will win. Do so now! */
5321 reload_cse_regs (first_insn);
5322 find_basic_blocks (first_insn);
5323 life_analysis (0, PROP_REG_INFO | PROP_DEATH_NOTES);
5325 /* Look for where absurd things are happening with DP. */
5326 mdr_try_dp_reload_elim (first_insn);
5328 ip2k_reorg_in_progress = 0;
5329 ip2k_reorg_completed = 1;
5331 split_all_insns (0);
5333 reload_cse_regs (first_insn);
5334 find_basic_blocks (first_insn);
5335 life_analysis (0, PROP_REG_INFO | PROP_DEATH_NOTES);
5336 if (flag_peephole2)
5337 peephole2_optimize (NULL);
5339 mdr_resequence_xy_yx (first_insn);
5340 mdr_propagate_reg_equivs (first_insn);
5342 /* Look for redundant set instructions. These can occur when we split
5343 instruction patterns and end up with the second half merging with
5344 or being replaced by something that clobbers the first half. */
5345 for (insn = first_insn; insn; insn = next_nonnote_insn (insn))
5347 if (GET_CODE (insn) == INSN)
5349 set = (GET_CODE (PATTERN (insn)) == SET) ? PATTERN (insn) : NULL_RTX;
5350 if ((set != NULL_RTX)
5351 && (GET_CODE (XEXP (set, 0)) == REG)
5352 && (GET_MODE (XEXP (set, 0)) == QImode)
5353 && (find_regno_note (insn, REG_UNUSED, REGNO (XEXP (set, 0)))))
5354 delete_insn (insn);
5358 mdr_try_move_dp_reload (first_insn);
5359 mdr_try_move_pushes (first_insn);
5361 find_basic_blocks (first_insn);
5362 life_analysis (0, PROP_FINAL);
5364 mdr_try_propagate_move (first_insn);
5365 mdr_resequence_xy_yx (first_insn);
5367 ip2k_reorg_split_dimode = 1;
5368 split_all_insns (0);
5370 mdr_try_remove_redundant_insns (first_insn);
5372 mdr_try_propagate_move (first_insn);
5374 reload_cse_regs (first_insn);
5375 find_basic_blocks (first_insn);
5376 life_analysis (0, PROP_FINAL);
5377 if (flag_peephole2)
5378 peephole2_optimize (NULL);
5380 mdr_try_propagate_move (first_insn);
5382 find_basic_blocks (first_insn);
5383 life_analysis (0, PROP_FINAL);
5385 ip2k_reorg_split_simode = 1;
5386 split_all_insns (0);
5388 mdr_try_remove_redundant_insns (first_insn);
5390 mdr_try_propagate_move (first_insn);
5392 reload_cse_regs (first_insn);
5393 find_basic_blocks (first_insn);
5394 life_analysis (0, PROP_FINAL);
5395 if (flag_peephole2)
5396 peephole2_optimize (NULL);
5398 mdr_try_propagate_move (first_insn);
5400 find_basic_blocks (first_insn);
5401 life_analysis (0, PROP_FINAL);
5403 ip2k_reorg_split_himode = 1;
5404 ip2k_reorg_merge_qimode = 1;
5405 split_all_insns (0);
5407 mdr_try_remove_redundant_insns (first_insn);
5408 mdr_try_propagate_clr (first_insn);
5409 mdr_try_propagate_move (first_insn);
5411 mdr_try_dp_reload_elim (first_insn);
5412 mdr_try_move_dp_reload (first_insn);
5414 rebuild_jump_labels (first_insn);
5416 /* Call to jump_optimize (...) was here, but now I removed it. */
5418 find_basic_blocks (first_insn);
5419 life_analysis (0, PROP_FINAL);
5420 if (flag_peephole2)
5421 peephole2_optimize (NULL);
5423 mdr_try_propagate_move (first_insn);
5425 find_basic_blocks (first_insn);
5426 life_analysis (0, PROP_FINAL);
5427 mdr_try_remove_redundant_insns (first_insn);
5429 mdr_try_propagate_clr (first_insn);
5430 mdr_try_propagate_move (first_insn);
5432 find_basic_blocks (first_insn);
5433 life_analysis (0, PROP_FINAL);
5435 ip2k_reorg_split_qimode = 1;
5436 split_all_insns (0);
5438 mdr_try_wreg_elim (first_insn);
5439 mdr_try_propagate_move (first_insn);
5441 find_basic_blocks (first_insn);
5442 life_analysis (0, PROP_FINAL);
5443 #endif
5446 static void
5447 ip2k_init_libfuncs (void)
5449 set_optab_libfunc (smul_optab, SImode, "_mulsi3");
5450 set_optab_libfunc (smul_optab, DImode, "_muldi3");
5451 set_optab_libfunc (cmp_optab, HImode, "_cmphi2");
5452 set_optab_libfunc (cmp_optab, SImode, "_cmpsi2");
5455 /* Returns a bit position if mask contains only a single bit. Returns -1 if
5456 there were zero or more than one set bits. */
5458 find_one_set_bit_p (HOST_WIDE_INT mask)
5460 int i;
5461 unsigned HOST_WIDE_INT n = mask;
5462 for (i = 0; i < 32; i++)
5464 if (n & 0x80000000UL)
5466 if (n & 0x7fffffffUL)
5467 return -1;
5468 else
5469 return 31 - i;
5471 n <<= 1;
5473 return -1;
5476 /* Returns a bit position if mask contains only a single clear bit.
5477 Returns -1 if there were zero or more than one clear bits. */
5479 find_one_clear_bit_p (HOST_WIDE_INT mask)
5481 int i;
5482 unsigned HOST_WIDE_INT n = mask;
5483 for (i = 0; i < 32; i++)
5485 if ((n & 0x80000000UL) == 0UL)
5487 if ((n & 0x7fffffffUL) != 0x7fffffffUL)
5488 return -1;
5489 else
5490 return 31 - i;
5492 n <<= 1;
5493 n |= 1;
5495 return -1;
5499 /* Split a move into two smaller pieces.
5500 MODE indicates the reduced mode. OPERANDS[0] is the original destination
5501 OPERANDS[1] is the original src. The new destinations are
5502 OPERANDS[2] and OPERANDS[4], while the new sources are OPERANDS[3]
5503 and OPERANDS[5]. */
5505 void
5506 ip2k_split_words (enum machine_mode nmode, enum machine_mode omode,
5507 rtx *operands)
5509 rtx dl, dh; /* src/dest pieces. */
5510 rtx sl, sh;
5511 int move_high_first = 0; /* Assume no overlap. */
5512 int pushflag = 0;
5514 switch (GET_CODE (operands[0])) /* DEST */
5516 case SUBREG:
5517 case REG:
5518 if ((GET_CODE (operands[1]) == REG
5519 || GET_CODE (operands[1]) == SUBREG)
5520 && (true_regnum (operands[0]) <= true_regnum (operands[1])
5521 || (true_regnum (operands[1])
5522 + GET_MODE_SIZE (omode) - 1 < true_regnum (operands[0]))))
5523 move_high_first = 1;
5525 if (GET_CODE (operands[0]) == SUBREG)
5527 dl = simplify_gen_subreg (nmode, operands[0], omode,
5528 GET_MODE_SIZE (nmode));
5529 dh = simplify_gen_subreg (nmode, operands[0], omode, 0);
5531 else if (GET_CODE (operands[0]) == REG && ! IS_PSEUDO_P (operands[0]))
5533 int r = REGNO (operands[0]);
5534 dh = gen_rtx_REG (nmode, r);
5535 dl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
5537 else
5539 dh = gen_rtx_SUBREG (nmode, operands[0], 0);
5540 dl = gen_rtx_SUBREG (nmode, operands[0], GET_MODE_SIZE (nmode));
5542 break;
5544 case MEM:
5545 switch (GET_CODE (XEXP (operands[0], 0)))
5547 case POST_INC:
5548 abort ();
5549 case POST_DEC:
5550 dl = dh = gen_rtx_MEM (nmode, XEXP (operands[0], 0));
5551 pushflag = 1;
5552 break;
5553 default:
5554 dl = change_address (operands[0], nmode,
5555 plus_constant (XEXP (operands[0], 0),
5556 GET_MODE_SIZE (nmode)));
5557 dh = gen_rtx_MEM (nmode, XEXP (operands[0], 0));
5559 break;
5560 default:
5561 abort ();
5564 switch (GET_CODE (operands[1]))
5566 case REG:
5567 if (! IS_PSEUDO_P (operands[1]))
5569 int r = REGNO (operands[1]);
5571 sh = gen_rtx_REG (nmode, r);
5572 sl = gen_rtx_REG (nmode, r + HARD_REGNO_NREGS (r, nmode));
5574 else
5576 sh = gen_rtx_SUBREG (nmode, operands[1], 0);
5577 sl = gen_rtx_SUBREG (nmode, operands[1], GET_MODE_SIZE (nmode));
5579 break;
5581 case CONST_DOUBLE:
5582 if (operands[1] == const0_rtx)
5583 sh = sl = const0_rtx;
5584 else
5586 if (GET_MODE (operands[0]) != DImode)
5588 REAL_VALUE_TYPE rv;
5589 long value;
5591 REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
5592 REAL_VALUE_TO_TARGET_SINGLE (rv, value);
5594 sh = gen_int_mode ((value >> 16) & 0xffff, nmode);
5595 sl = gen_int_mode (value & 0xffff, nmode);
5597 else
5599 sh = gen_int_mode (CONST_DOUBLE_HIGH (operands[1]), nmode);
5600 sl = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), nmode);
5603 break;
5605 case CONST_INT:
5606 if (operands[1] == const0_rtx)
5607 sh = sl = const0_rtx;
5608 else
5610 int val = INTVAL (operands[1]);
5611 int vl, vh;
5613 switch (nmode)
5615 case QImode:
5616 vh = (val >> 8) & 0xff;
5617 vl = val & 0xff;
5618 break;
5620 case HImode:
5621 vh = (val >> 16) & 0xffff;
5622 vl = val & 0xffff;
5623 break;
5625 case SImode:
5626 if (val < 0) /* sign extend */
5627 vh = -1;
5628 else
5629 vh = 0;
5630 vl = val; /* Give low 32 bits back. */
5631 break;
5633 default:
5634 abort ();
5637 sl = gen_int_mode (vl, nmode);
5638 sh = gen_int_mode (vh, nmode);
5640 break;
5642 case SUBREG:
5643 sl = simplify_gen_subreg (nmode, operands[1], omode,
5644 GET_MODE_SIZE (nmode));
5645 sh = simplify_gen_subreg (nmode, operands[1], omode, 0);
5646 break;
5648 case MEM:
5649 switch (GET_CODE (XEXP (operands[1], 0)))
5651 case POST_DEC:
5652 case POST_INC:
5653 abort ();
5654 break;
5656 default:
5657 /* Worry about splitting stack pushes. */
5658 if (pushflag && ip2k_address_uses_reg_p (operands[1], REG_SP))
5659 sl = sh = change_address (operands[1], nmode,
5660 plus_constant (XEXP (operands[1], 0),
5661 GET_MODE_SIZE (nmode)));
5662 else
5664 sl = change_address (operands[1], nmode,
5665 plus_constant (XEXP (operands[1], 0),
5666 GET_MODE_SIZE (nmode)));
5667 sh = gen_rtx_MEM (nmode, XEXP (operands[1], 0));
5670 break;
5672 default:
5673 abort ();
5676 if (move_high_first)
5678 operands[2] = dh;
5679 operands[3] = sh;
5680 operands[4] = dl;
5681 operands[5] = sl;
5683 else
5685 operands[2] = dl;
5686 operands[3] = sl;
5687 operands[4] = dh;
5688 operands[5] = sh;
5690 return;
5693 /* Get the low half of an operand. */
5695 ip2k_get_low_half (rtx x, enum machine_mode mode)
5697 switch (GET_CODE (x))
5699 case REG:
5700 if (! IS_PSEUDO_P (x))
5702 unsigned int r = REGNO (x);
5704 return gen_rtx_REG (mode, r + HARD_REGNO_NREGS (r, mode));
5706 else
5708 return gen_rtx_SUBREG (mode, x, GET_MODE_SIZE (mode));
5710 break;
5712 case CONST_DOUBLE:
5713 if (x == const0_rtx)
5714 return const0_rtx;
5715 else
5717 if (mode != SImode)
5719 REAL_VALUE_TYPE rv;
5720 long value;
5722 REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
5723 REAL_VALUE_TO_TARGET_SINGLE (rv, value);
5725 return gen_int_mode (value & 0xffff, mode);
5727 else
5728 return gen_int_mode (CONST_DOUBLE_LOW (x), mode);
5730 break;
5732 case CONST_INT:
5733 if (x == const0_rtx)
5734 return const0_rtx;
5735 else
5737 int val = INTVAL (x);
5738 int vl, vh;
5740 switch (mode)
5742 case QImode:
5743 vh = (val >> 8) & 0xff;
5744 vl = val & 0xff;
5745 break;
5747 case HImode:
5748 vh = (val >> 16) & 0xffff;
5749 vl = val & 0xffff;
5750 break;
5752 case SImode:
5753 if (val < 0) /* sign extend */
5754 vh = -1;
5755 else
5756 vh = 0;
5757 vl = val; /* Give low 32 bits back. */
5758 break;
5760 default:
5761 abort ();
5764 return gen_int_mode (vl, mode);
5766 break;
5768 case SUBREG:
5769 return simplify_gen_subreg (mode, x, GET_MODE (x), GET_MODE_SIZE (mode));
5771 case MEM:
5772 switch (GET_CODE (XEXP (x, 0)))
5774 case POST_DEC:
5775 case POST_INC:
5776 abort ();
5777 break;
5779 default:
5780 return change_address (x, mode,
5781 plus_constant (XEXP (x, 0),
5782 GET_MODE_SIZE (mode)));
5784 break;
5786 default:
5787 abort ();
5789 return NULL_RTX;
5792 /* Get the high half of an operand. */
5794 ip2k_get_high_half (rtx x, enum machine_mode mode)
5796 switch (GET_CODE (x))
5798 case REG:
5799 if (! IS_PSEUDO_P (x))
5801 unsigned int r = REGNO (x);
5803 return gen_rtx_REG (mode, r);
5805 else
5807 return gen_rtx_SUBREG (mode, x, 0);
5809 break;
5811 case CONST_DOUBLE:
5812 if (x == const0_rtx)
5813 return const0_rtx;
5814 else
5816 if (mode != SImode)
5818 REAL_VALUE_TYPE rv;
5819 long value;
5821 REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
5822 REAL_VALUE_TO_TARGET_SINGLE (rv, value);
5824 return gen_int_mode ((value >> 16) & 0xffff, mode);
5826 else
5827 return gen_int_mode (CONST_DOUBLE_HIGH (x), mode);
5829 break;
5831 case CONST_INT:
5832 if (x == const0_rtx)
5833 return const0_rtx;
5834 else
5836 int val = INTVAL (x);
5837 int vl, vh;
5839 switch (mode)
5841 case QImode:
5842 vh = (val >> 8) & 0xff;
5843 vl = val & 0xff;
5844 break;
5846 case HImode:
5847 vh = (val >> 16) & 0xffff;
5848 vl = val & 0xffff;
5849 break;
5851 case SImode:
5852 if (val < 0) /* sign extend */
5853 vh = -1;
5854 else
5855 vh = 0;
5856 vl = val; /* Give low 32 bits back. */
5857 break;
5859 default:
5860 abort ();
5863 return gen_int_mode (vh, mode);
5865 break;
5867 case SUBREG:
5868 return simplify_gen_subreg (mode, x, GET_MODE (x), 0);
5869 break;
5871 case MEM:
5872 switch (GET_CODE (XEXP (x, 0)))
5874 case POST_DEC:
5875 case POST_INC:
5876 abort ();
5877 break;
5879 default:
5880 return change_address (x, mode, plus_constant (XEXP (x, 0), 0));
5882 break;
5884 default:
5885 abort ();
5887 return NULL_RTX;
5890 /* Does address X use register R. Only valid for REG_SP, REG_DP, REG_IP
5891 or REG_FP. */
5894 ip2k_address_uses_reg_p (rtx x, unsigned int r)
5896 if (GET_CODE (x) != MEM)
5897 return 0;
5899 x = XEXP (x, 0);
5901 while (1)
5902 switch (GET_CODE (x))
5904 case POST_DEC:
5905 case POST_INC:
5906 case PRE_DEC:
5907 case PRE_INC:
5908 x = XEXP (x, 0);
5909 break;
5911 case PLUS:
5912 if (ip2k_address_uses_reg_p (XEXP (x, 1), r))
5913 return 1;
5915 x = XEXP (x, 0);
5916 break;
5918 case SUBREG:
5919 /* Ignore subwords. */
5920 x = SUBREG_REG (x);
5921 break;
5923 case REG:
5924 /* Have to consider that r might be LSB of a pointer reg. */
5925 return ((REGNO (x) == r) || (REGNO (x) == (r - 1))) ? 1 : 0;
5927 case MEM:
5928 /* We might be looking at a (mem:BLK (mem (...))) */
5929 x = XEXP (x, 0);
5930 break;
5932 default:
5933 return 0;
5937 /* Does the queried XEXP not use a particular register? If we're certain
5938 that it doesn't then we return TRUE otherwise we assume FALSE. */
5941 ip2k_xexp_not_uses_reg_p (rtx x, unsigned int r, int rsz)
5943 switch (GET_CODE (x))
5945 case REG:
5947 int msz = GET_MODE_SIZE (GET_MODE (x));
5949 return (((REGNO (x) + msz - 1) < r)
5950 || (REGNO (x) > (r + rsz - 1)));
5953 case MEM:
5954 return !ip2k_address_uses_reg_p (x, r);
5956 case LABEL_REF:
5957 case SYMBOL_REF:
5958 case CONST:
5959 case CONST_INT:
5960 case CONST_DOUBLE:
5961 case CC0:
5962 case PC:
5963 return 1;
5965 default:
5966 return 0;
5970 /* Does the queried XEXP not use a particular register? If we're certain
5971 that it doesn't then we return TRUE otherwise we assume FALSE. */
5974 ip2k_composite_xexp_not_uses_reg_p (rtx x, unsigned int r, int rsz)
5976 if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS)
5977 return (ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz)
5978 && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 1), r, rsz)
5979 && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 2), r, rsz));
5981 if (BINARY_P (x))
5982 return (ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz)
5983 && ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 1), r, rsz));
5985 if (UNARY_P (x)
5986 || GET_RTX_CLASS (GET_CODE (x)) == RTX_TERNARY)
5987 return ip2k_composite_xexp_not_uses_reg_p (XEXP (x, 0), r, rsz);
5989 return ip2k_xexp_not_uses_reg_p (x, r, rsz);
5992 /* Does the queried XEXP not use CC0? If we're certain that
5993 it doesn't then we return TRUE otherwise we assume FALSE. */
5996 ip2k_composite_xexp_not_uses_cc0_p (rtx x)
5998 if (GET_RTX_CLASS (GET_CODE (x)) == RTX_BITFIELD_OPS)
5999 return (ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0))
6000 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 1))
6001 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 2)));
6003 if (BINARY_P (x))
6004 return (ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0))
6005 && ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 1)));
6007 if (UNARY_P (x)
6008 || GET_RTX_CLASS (GET_CODE (x)) == RTX_TERNARY)
6009 return ip2k_composite_xexp_not_uses_cc0_p (XEXP (x, 0));
6011 return GET_CODE (x) != CC0;
6015 ip2k_split_dest_operand (rtx x, enum machine_mode mode)
6017 return nonimmediate_operand (x, mode) || push_operand (x, mode);
6021 ip2k_nonptr_operand (rtx x, enum machine_mode mode)
6023 return register_operand (x, mode) && !ip2k_ptr_operand (x, mode);
6026 /* Is X a reference to IP or DP or SP? */
6029 ip2k_ptr_operand (rtx x, enum machine_mode mode)
6032 if (GET_CODE (x) == SUBREG)
6033 x = SUBREG_REG (x);
6035 return (REG_P (x)
6036 && (mode == HImode || mode == VOIDmode)
6037 && (REGNO (x) == REG_IP
6038 || REGNO (x) == REG_DP
6039 || REGNO (x) == REG_SP));
6043 ip2k_sp_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
6046 return REG_P (x) && REGNO (x) == REG_SP;
6050 ip2k_ip_operand (rtx x, enum machine_mode mode)
6053 if (GET_CODE (x) != MEM)
6054 return 0;
6056 x = XEXP (x, 0);
6058 if (GET_CODE (x) == PLUS && XEXP (x, 1) == const0_rtx)
6059 x = XEXP (x, 0);
6061 if (! REG_P (x))
6062 return 0;
6064 if (GET_MODE_SIZE (mode) > 1)
6065 return 0; /* Can't access offset bytes. */
6067 return REGNO (x) == REG_IP;
6070 /* Is X a memory address suitable for SP or DP relative addressing? */
6072 ip2k_short_operand (rtx x, enum machine_mode mode)
6074 int r;
6075 unsigned int offs = 0;
6077 if (! memory_operand (x, mode))
6078 return 0; /* Got to be a memory address. */
6080 x = XEXP (x, 0);
6081 switch (GET_CODE (x))
6083 default:
6084 return 0;
6086 case PLUS:
6087 if (! REG_P (XEXP (x, 0))
6088 || GET_CODE (XEXP (x, 1)) != CONST_INT)
6089 return 0;
6091 offs = INTVAL (XEXP (x, 1));
6093 if (128 <= offs)
6094 return 0;
6096 x = XEXP (x, 0);
6098 /* fall through */
6100 case REG:
6101 if (IS_PSEUDO_P (x))
6102 return 0; /* Optimistic - doesn't work. */
6104 r = REGNO (x);
6106 /* For 'S' constraint, we presume that no IP adjustment
6107 simulation is performed - so only QI mode allows IP to be a
6108 short offset address. All other IP references must be
6109 handled by 'R' constraints. */
6110 if (r == REG_IP && offs == 0 && GET_MODE_SIZE (mode) <= 1)
6111 return 1;
6113 return (r == REG_SP || r == REG_DP);
6118 ip2k_nonsp_reg_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
6120 if (GET_CODE (x) == SUBREG)
6121 x = SUBREG_REG (x);
6123 return (REG_P (x) && REGNO (x) != REG_SP);
6127 ip2k_gen_operand (rtx x, enum machine_mode mode)
6129 return ip2k_short_operand (x, mode)
6130 || (GET_CODE (x) == SUBREG
6131 && REG_P (SUBREG_REG (x)))
6132 || (ip2k_nonsp_reg_operand (x, mode));
6136 ip2k_extra_constraint (rtx x, int c)
6138 switch (c)
6140 case 'S': /* Allow offset in stack frame... */
6141 return ip2k_short_operand (x, GET_MODE (x));
6143 case 'R':
6144 return ip2k_ip_operand (x, GET_MODE (x));
6146 case 'T': /* Constant int or .data address. */
6147 return CONSTANT_P (x) && is_regfile_address (x);
6149 default:
6150 return 0;
6155 ip2k_unary_operator (rtx op, enum machine_mode mode)
6157 return ((mode == VOIDmode || GET_MODE (op) == mode)
6158 && UNARY_P (op));
6162 ip2k_binary_operator (rtx op, enum machine_mode mode)
6164 return ((mode == VOIDmode || GET_MODE (op) == mode)
6165 && ARITHMETIC_P (op));
6169 ip2k_symbol_ref_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
6171 /* We define an IP2k symbol ref to be either a direct reference or one
6172 with a constant offset. */
6173 return (GET_CODE (op) == SYMBOL_REF)
6174 || (GET_CODE (op) == CONST
6175 && GET_CODE (XEXP (op, 0)) == PLUS
6176 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF);
6180 ip2k_signed_comparison_operator (rtx op, enum machine_mode mode)
6182 return (comparison_operator (op, mode)
6183 && signed_condition (GET_CODE (op)) == GET_CODE (op));
6187 ip2k_unsigned_comparison_operator (rtx op, enum machine_mode mode)
6189 return (comparison_operator (op, mode)
6190 && unsigned_condition (GET_CODE (op)) == GET_CODE (op));
6193 /* Worker function for TARGET_RETURN_IN_MEMORY. */
6195 static bool
6196 ip2k_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
6198 if (TYPE_MODE (type) == BLKmode)
6200 HOST_WIDE_INT size = int_size_in_bytes (type);
6201 return (size == -1 || size > 8);
6203 else
6204 return false;
6207 /* Worker function for TARGET_SETUP_INCOMING_VARARGS. */
6209 static void
6210 ip2k_setup_incoming_varargs (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
6211 enum machine_mode mode ATTRIBUTE_UNUSED,
6212 tree type ATTRIBUTE_UNUSED,
6213 int *pretend_arg_size,
6214 int second_time ATTRIBUTE_UNUSED)
6216 *pretend_arg_size = 0;