Merge from mainline (167278:168000).
[official-gcc/graphite-test-results.git] / gcc / config / microblaze / microblaze.c
blobb50c7942e0d471fbedd72414e301a0dd3eedf01e
1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright 2009, 2010 Free Software Foundation, Inc.
4 Contributed by Michael Eager <eager@eagercon.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "real.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
33 #include "insn-attr.h"
34 #include "integrate.h"
35 #include "recog.h"
36 #include "tree.h"
37 #include "function.h"
38 #include "expr.h"
39 #include "flags.h"
40 #include "reload.h"
41 #include "output.h"
42 #include "ggc.h"
43 #include "hashtab.h"
44 #include "target.h"
45 #include "target-def.h"
46 #include "tm_p.h"
47 #include "gstab.h"
48 #include "df.h"
49 #include "optabs.h"
50 #include "diagnostic-core.h"
52 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
54 /* Classifies an address.
56 ADDRESS_INVALID
57 An invalid address.
59 ADDRESS_REG
61 A natural register or a register + const_int offset address.
62 The register satisfies microblaze_valid_base_register_p and the
63 offset is a const_arith_operand.
65 ADDRESS_REG_INDEX
67 A natural register offset by the index contained in an index register. The base
68 register satisfies microblaze_valid_base_register_p and the index register
69 satisfies microblaze_valid_index_register_p
71 ADDRESS_CONST_INT
73 A signed 16/32-bit constant address.
75 ADDRESS_SYMBOLIC:
77 A constant symbolic address or a (register + symbol). */
79 enum microblaze_address_type
81 ADDRESS_INVALID,
82 ADDRESS_REG,
83 ADDRESS_REG_INDEX,
84 ADDRESS_CONST_INT,
85 ADDRESS_SYMBOLIC,
86 ADDRESS_GOTOFF,
87 ADDRESS_PLT
90 /* Classifies symbols
92 SYMBOL_TYPE_GENERAL
94 A general symbol. */
95 enum microblaze_symbol_type
97 SYMBOL_TYPE_INVALID,
98 SYMBOL_TYPE_GENERAL
101 /* Classification of a MicroBlaze address. */
102 struct microblaze_address_info
104 enum microblaze_address_type type;
105 rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
106 ADDRESS_SYMBOLIC. */
107 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
108 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
109 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
110 enum microblaze_symbol_type symbol_type;
113 /* Structure to be filled in by compute_frame_size with register
114 save masks, and offsets for the current function. */
116 struct GTY(()) microblaze_frame_info {
117 long total_size; /* # bytes that the entire frame takes up. */
118 long var_size; /* # bytes that variables take up. */
119 long args_size; /* # bytes that outgoing arguments take up. */
120 int link_debug_size; /* # bytes for the link reg and back pointer. */
121 int gp_reg_size; /* # bytes needed to store gp regs. */
122 long gp_offset; /* offset from new sp to store gp registers. */
123 long mask; /* mask of saved gp registers. */
124 int initialized; /* != 0 if frame size already calculated. */
125 int num_gp; /* number of gp registers saved. */
126 long insns_len; /* length of insns. */
127 int alloc_stack; /* Flag to indicate if the current function
128 must not create stack space. (As an optimization). */
131 /* Global variables for machine-dependent things. */
133 /* Toggle which pipleline interface to use. */
134 static GTY(()) int microblaze_sched_use_dfa = 0;
136 /* Threshold for data being put into the small data/bss area, instead
137 of the normal data area (references to the small data/bss area take
138 1 instruction, and use the global pointer, references to the normal
139 data area takes 2 instructions). */
140 int microblaze_section_threshold = -1;
142 /* Prevent scheduling potentially exception causing instructions in
143 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
144 int microblaze_no_unsafe_delay;
146 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
147 version having only a particular type of pipeline. There can still be
148 options on the CPU to scale pipeline features up or down. :(
149 Bad Presentation (??), so we let the MD file rely on the value of
150 this variable instead Making PIPE_5 the default. It should be backward
151 optimal with PIPE_3 MicroBlazes. */
152 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
154 /* High and low marks for floating point values which we will accept
155 as legitimate constants for LEGITIMATE_CONSTANT_P. These are
156 initialized in override_options. */
157 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
159 /* Array giving truth value on whether or not a given hard register
160 can support a given mode. */
161 char microblaze_hard_regno_mode_ok[(int)MAX_MACHINE_MODE]
162 [FIRST_PSEUDO_REGISTER];
164 /* Current frame information calculated by compute_frame_size. */
165 struct microblaze_frame_info current_frame_info;
167 /* Zero structure to initialize current_frame_info. */
168 struct microblaze_frame_info zero_frame_info;
170 /* List of all MICROBLAZE punctuation characters used by print_operand. */
171 char microblaze_print_operand_punct[256];
173 /* Map GCC register number to debugger register number. */
174 int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
176 /* Map hard register number to register class. */
177 enum reg_class microblaze_regno_to_class[] =
179 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
180 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
181 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
182 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
183 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
184 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
185 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
186 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
187 ST_REGS, GR_REGS, GR_REGS, GR_REGS
190 /* MicroBlaze specific machine attributes.
191 interrupt_handler - Interrupt handler attribute to add interrupt prologue
192 and epilogue and use appropriate interrupt return.
193 save_volatiles - Similiar to interrupt handler, but use normal return. */
194 int interrupt_handler;
195 int save_volatiles;
197 const struct attribute_spec microblaze_attribute_table[] = {
198 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler */
199 {"interrupt_handler", 0, 0, true, false, false, NULL},
200 {"save_volatiles" , 0, 0, true, false, false, NULL},
201 { NULL, 0, 0, false, false, false, NULL}
204 static int microblaze_interrupt_function_p (tree);
206 section *sdata2_section;
208 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
210 microblaze_const_double_ok (rtx op, enum machine_mode mode)
212 REAL_VALUE_TYPE d;
214 if (GET_CODE (op) != CONST_DOUBLE)
215 return 0;
217 if (mode == VOIDmode)
218 return 1;
220 if (mode != SFmode && mode != DFmode)
221 return 0;
223 if (op == CONST0_RTX (mode))
224 return 1;
226 REAL_VALUE_FROM_CONST_DOUBLE (d, op);
228 if (REAL_VALUE_ISNAN (d))
229 return FALSE;
231 if (REAL_VALUE_NEGATIVE (d))
232 d = real_value_negate (&d);
234 if (mode == DFmode)
236 if (REAL_VALUES_LESS (d, dfhigh) && REAL_VALUES_LESS (dflow, d))
237 return 1;
239 else
241 if (REAL_VALUES_LESS (d, sfhigh) && REAL_VALUES_LESS (sflow, d))
242 return 1;
245 return 0;
248 /* Return truth value if a memory operand fits in a single instruction
249 (ie, register + small offset) or (register + register). */
252 simple_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
254 rtx addr, plus0, plus1;
256 /* Eliminate non-memory operations. */
257 if (GET_CODE (op) != MEM)
258 return 0;
260 /* dword operations really put out 2 instructions, so eliminate them. */
261 /* ??? This isn't strictly correct. It is OK to accept multiword modes
262 here, since the length attributes are being set correctly, but only
263 if the address is offsettable. */
264 if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
265 return 0;
268 /* Decode the address now. */
269 addr = XEXP (op, 0);
270 switch (GET_CODE (addr))
273 case REG:
274 return 1;
276 case PLUS:
277 plus0 = XEXP (addr, 0);
278 plus1 = XEXP (addr, 1);
280 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
281 && SMALL_INT (plus1))
283 return 1;
285 else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
287 return 1;
289 else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
291 return 1;
293 else
294 return 0;
296 case SYMBOL_REF:
297 return 0;
299 default:
300 break;
303 return 0;
306 /* Return nonzero for a memory address that can be used to load or store
307 a doubleword. */
310 double_memory_operand (rtx op, enum machine_mode mode)
312 rtx addr;
314 if (GET_CODE (op) != MEM || !memory_operand (op, mode))
316 /* During reload, we accept a pseudo register if it has an
317 appropriate memory address. If we don't do this, we will
318 wind up reloading into a register, and then reloading that
319 register from memory, when we could just reload directly from
320 memory. */
321 if (reload_in_progress
322 && GET_CODE (op) == REG
323 && REGNO (op) >= FIRST_PSEUDO_REGISTER
324 && reg_renumber[REGNO (op)] < 0
325 && reg_equiv_mem[REGNO (op)] != 0
326 && double_memory_operand (reg_equiv_mem[REGNO (op)], mode))
327 return 1;
328 return 0;
331 /* Make sure that 4 added to the address is a valid memory address.
332 This essentially just checks for overflow in an added constant. */
334 addr = XEXP (op, 0);
336 if (CONSTANT_ADDRESS_P (addr))
337 return 1;
339 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
340 ? SImode : SFmode), plus_constant (addr, 4));
343 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
345 microblaze_regno_ok_for_base_p (int regno, int strict)
347 if (regno >= FIRST_PSEUDO_REGISTER)
349 if (!strict)
350 return true;
351 regno = reg_renumber[regno];
354 /* These fake registers will be eliminated to either the stack or
355 hard frame pointer, both of which are usually valid base registers.
356 Reload deals with the cases where the eliminated form isn't valid. */
357 if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
358 return true;
360 return GP_REG_P (regno);
363 /* Return true if X is a valid base register for the given mode.
364 Allow only hard registers if STRICT. */
366 static bool
367 microblaze_valid_base_register_p (rtx x,
368 enum machine_mode mode ATTRIBUTE_UNUSED,
369 int strict)
371 if (!strict && GET_CODE (x) == SUBREG)
372 x = SUBREG_REG (x);
374 return (GET_CODE (x) == REG
375 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
378 static bool
379 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
381 info->symbol_type = SYMBOL_TYPE_GENERAL;
382 info->symbol = XVECEXP (x, 0, 0);
384 if (XINT (x, 1) == UNSPEC_GOTOFF)
386 info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
387 info->type = ADDRESS_GOTOFF;
389 else if (XINT (x, 1) == UNSPEC_PLT)
391 info->type = ADDRESS_PLT;
393 else
395 return false;
397 return true;
401 /* Return true if X is a valid index register for the given mode.
402 Allow only hard registers if STRICT. */
404 static bool
405 microblaze_valid_index_register_p (rtx x,
406 enum machine_mode mode ATTRIBUTE_UNUSED,
407 int strict)
409 if (!strict && GET_CODE (x) == SUBREG)
410 x = SUBREG_REG (x);
412 return (GET_CODE (x) == REG
413 /* A base register is good enough to be an index register on MicroBlaze. */
414 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
417 /* Get the base register for accessing a value from the memory or
418 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
419 static int
420 get_base_reg (rtx x)
422 tree decl;
423 int base_reg = (flag_pic ? MB_ABI_PIC_ADDR_REGNUM : MB_ABI_BASE_REGNUM);
425 if (TARGET_XLGPOPT
426 && GET_CODE (x) == SYMBOL_REF
427 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
429 if (TREE_READONLY (decl))
430 base_reg = MB_ABI_GPRO_REGNUM;
431 else
432 base_reg = MB_ABI_GPRW_REGNUM;
435 return base_reg;
438 /* Return true if X is a valid address for machine mode MODE. If it is,
439 fill in INFO appropriately. STRICT is true if we should only accept
440 hard base registers.
442 type regA regB offset symbol
444 ADDRESS_INVALID NULL NULL NULL NULL
446 ADDRESS_REG %0 NULL const_0 / NULL
447 const_int
448 ADDRESS_REG_INDEX %0 %1 NULL NULL
450 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
451 sda_base_reg
453 ADDRESS_CONST_INT r0 NULL const NULL
455 For modes spanning multiple registers (DFmode in 32-bit GPRs,
456 DImode, TImode), indexed addressing cannot be used because
457 adjacent memory cells are accessed by adding word-sized offsets
458 during assembly output. */
460 static bool
461 microblaze_classify_address (struct microblaze_address_info *info, rtx x,
462 enum machine_mode mode, int strict)
464 rtx xplus0;
465 rtx xplus1;
467 info->type = ADDRESS_INVALID;
468 info->regA = NULL;
469 info->regB = NULL;
470 info->offset = NULL;
471 info->symbol = NULL;
472 info->symbol_type = SYMBOL_TYPE_INVALID;
474 switch (GET_CODE (x))
476 case REG:
477 case SUBREG:
479 info->type = ADDRESS_REG;
480 info->regA = x;
481 info->offset = const0_rtx;
482 return microblaze_valid_base_register_p (info->regA, mode, strict);
484 case PLUS:
486 xplus0 = XEXP (x, 0);
487 xplus1 = XEXP (x, 1);
489 if (microblaze_valid_base_register_p (xplus0, mode, strict))
491 info->type = ADDRESS_REG;
492 info->regA = xplus0;
494 if (GET_CODE (xplus1) == CONST_INT)
496 info->offset = xplus1;
497 return true;
499 else if (GET_CODE (xplus1) == UNSPEC)
501 return microblaze_classify_unspec (info, xplus1);
503 else if ((GET_CODE (xplus1) == SYMBOL_REF ||
504 GET_CODE (xplus1) == LABEL_REF) && flag_pic == 2)
506 return false;
508 else if (GET_CODE (xplus1) == SYMBOL_REF ||
509 GET_CODE (xplus1) == LABEL_REF ||
510 GET_CODE (xplus1) == CONST)
512 if (GET_CODE (XEXP (xplus1, 0)) == UNSPEC)
513 return microblaze_classify_unspec (info, XEXP (xplus1, 0));
514 else if (flag_pic == 2)
516 return false;
518 info->type = ADDRESS_SYMBOLIC;
519 info->symbol = xplus1;
520 info->symbol_type = SYMBOL_TYPE_GENERAL;
521 return true;
523 else if (GET_CODE (xplus1) == REG
524 && microblaze_valid_index_register_p (xplus1, mode,
525 strict)
526 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
528 /* Restrict larger than word-width modes from using an index register. */
529 info->type = ADDRESS_REG_INDEX;
530 info->regB = xplus1;
531 return true;
534 break;
536 case CONST_INT:
538 info->regA = gen_rtx_raw_REG (mode, 0);
539 info->type = ADDRESS_CONST_INT;
540 info->offset = x;
541 return true;
543 case CONST:
544 case LABEL_REF:
545 case SYMBOL_REF:
547 info->type = ADDRESS_SYMBOLIC;
548 info->symbol_type = SYMBOL_TYPE_GENERAL;
549 info->symbol = x;
550 info->regA = gen_rtx_raw_REG (mode, get_base_reg (x));
552 if (GET_CODE (x) == CONST)
554 return !(flag_pic && pic_address_needs_scratch (x));
556 else if (flag_pic == 2)
558 return false;
561 return true;
564 case UNSPEC:
566 if (reload_in_progress)
567 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
568 return microblaze_classify_unspec (info, x);
571 default:
572 return false;
575 return false;
578 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
579 returns a nonzero value if X is a legitimate address for a memory
580 operand of the indicated MODE. STRICT is nonzero if this function
581 is called during reload. */
583 bool
584 microblaze_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
586 struct microblaze_address_info addr;
588 return microblaze_classify_address (&addr, x, mode, strict);
592 /* Try machine-dependent ways of modifying an illegitimate address
593 to be legitimate. If we find one, return the new, valid address.
594 This is used from only one place: `memory_address' in explow.c.
596 OLDX is the address as it was before break_out_memory_refs was
597 called. In some cases it is useful to look at this to decide what
598 needs to be done.
600 It is always safe for this function to do nothing. It exists to
601 recognize opportunities to optimize the output.
603 For the MicroBlaze, transform:
605 memory(X + <large int>)
607 into:
609 Y = <large int> & ~0x7fff;
610 Z = X + Y
611 memory (Z + (<large int> & 0x7fff));
613 This is for CSE to find several similar references, and only use one Z.
615 When PIC, convert addresses of the form memory (symbol+large int) to
616 memory (reg+large int). */
618 static rtx
619 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
620 enum machine_mode mode ATTRIBUTE_UNUSED)
622 register rtx xinsn = x, result;
624 if (GET_CODE (xinsn) == CONST
625 && flag_pic && pic_address_needs_scratch (xinsn))
627 rtx ptr_reg = gen_reg_rtx (Pmode);
628 rtx constant = XEXP (XEXP (xinsn, 0), 1);
630 emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
632 result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
633 if (SMALL_INT (constant))
634 return result;
635 /* Otherwise we fall through so the code below will fix the
636 constant. */
637 xinsn = result;
640 if (GET_CODE (xinsn) == PLUS)
642 register rtx xplus0 = XEXP (xinsn, 0);
643 register rtx xplus1 = XEXP (xinsn, 1);
644 register enum rtx_code code0 = GET_CODE (xplus0);
645 register enum rtx_code code1 = GET_CODE (xplus1);
647 if (code0 != REG && code1 == REG)
649 xplus0 = XEXP (xinsn, 1);
650 xplus1 = XEXP (xinsn, 0);
651 code0 = GET_CODE (xplus0);
652 code1 = GET_CODE (xplus1);
655 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
656 && code1 == CONST_INT && !SMALL_INT (xplus1))
658 rtx int_reg = gen_reg_rtx (Pmode);
659 rtx ptr_reg = gen_reg_rtx (Pmode);
661 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
663 emit_insn (gen_rtx_SET (VOIDmode,
664 ptr_reg,
665 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
667 result = gen_rtx_PLUS (Pmode, ptr_reg,
668 GEN_INT (INTVAL (xplus1) & 0x7fff));
669 return result;
672 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0) && flag_pic == 2)
674 if (reload_in_progress)
675 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
676 if (code1 == CONST)
678 xplus1 = XEXP (xplus1, 0);
679 code1 = GET_CODE (xplus1);
681 if (code1 == SYMBOL_REF)
683 result =
684 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1), UNSPEC_GOTOFF);
685 result = gen_rtx_CONST (Pmode, result);
686 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
687 result = gen_const_mem (Pmode, result);
688 result = gen_rtx_PLUS (Pmode, xplus0, result);
689 return result;
694 if (GET_CODE (xinsn) == SYMBOL_REF)
696 if (reload_in_progress)
697 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
698 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
699 result = gen_rtx_CONST (Pmode, result);
700 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
701 result = gen_const_mem (Pmode, result);
702 return result;
705 return x;
708 /* Block Moves. */
710 #define MAX_MOVE_REGS 8
711 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
713 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
714 Assume that the areas do not overlap. */
716 static void
717 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
719 HOST_WIDE_INT offset, delta;
720 unsigned HOST_WIDE_INT bits;
721 int i;
722 enum machine_mode mode;
723 rtx *regs;
725 bits = BITS_PER_WORD;
726 mode = mode_for_size (bits, MODE_INT, 0);
727 delta = bits / BITS_PER_UNIT;
729 /* Allocate a buffer for the temporary registers. */
730 regs = XALLOCAVEC (rtx, length / delta);
732 /* Load as many BITS-sized chunks as possible. Use a normal load if
733 the source has enough alignment, otherwise use left/right pairs. */
734 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
736 regs[i] = gen_reg_rtx (mode);
737 emit_move_insn (regs[i], adjust_address (src, mode, offset));
740 /* Copy the chunks to the destination. */
741 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
742 emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
744 /* Mop up any left-over bytes. */
745 if (offset < length)
747 src = adjust_address (src, BLKmode, offset);
748 dest = adjust_address (dest, BLKmode, offset);
749 move_by_pieces (dest, src, length - offset,
750 MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0);
754 /* Helper function for doing a loop-based block operation on memory
755 reference MEM. Each iteration of the loop will operate on LENGTH
756 bytes of MEM.
758 Create a new base register for use within the loop and point it to
759 the start of MEM. Create a new memory reference that uses this
760 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
762 static void
763 microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
764 rtx * loop_reg, rtx * loop_mem)
766 *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
768 /* Although the new mem does not refer to a known location,
769 it does keep up to LENGTH bytes of alignment. */
770 *loop_mem = change_address (mem, BLKmode, *loop_reg);
771 set_mem_align (*loop_mem,
772 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
773 length * BITS_PER_UNIT));
777 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
778 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
779 memory regions do not overlap. */
781 static void
782 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
784 rtx label, src_reg, dest_reg, final_src;
785 HOST_WIDE_INT leftover;
787 leftover = length % MAX_MOVE_BYTES;
788 length -= leftover;
790 /* Create registers and memory references for use within the loop. */
791 microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
792 microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
794 /* Calculate the value that SRC_REG should have after the last iteration
795 of the loop. */
796 final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
797 0, 0, OPTAB_WIDEN);
799 /* Emit the start of the loop. */
800 label = gen_label_rtx ();
801 emit_label (label);
803 /* Emit the loop body. */
804 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
806 /* Move on to the next block. */
807 emit_move_insn (src_reg, plus_constant (src_reg, MAX_MOVE_BYTES));
808 emit_move_insn (dest_reg, plus_constant (dest_reg, MAX_MOVE_BYTES));
810 /* Emit the test & branch. */
811 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
812 src_reg, final_src, label));
814 /* Mop up any left-over bytes. */
815 if (leftover)
816 microblaze_block_move_straight (dest, src, leftover);
819 /* Expand a movmemsi instruction. */
821 bool
822 microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
825 if (GET_CODE (length) == CONST_INT)
827 HOST_WIDE_INT bytes = INTVAL (length);
828 int align = INTVAL (align_rtx);
830 if (align > UNITS_PER_WORD)
832 align = UNITS_PER_WORD; /* We can't do any better. */
834 else if (align < UNITS_PER_WORD)
836 if (INTVAL (length) <= MAX_MOVE_BYTES)
838 move_by_pieces (dest, src, bytes, align, 0);
839 return true;
841 else
842 return false;
845 if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
847 microblaze_block_move_straight (dest, src, INTVAL (length));
848 return true;
850 else if (optimize)
852 microblaze_block_move_loop (dest, src, INTVAL (length));
853 return true;
856 return false;
859 static bool
860 microblaze_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total,
861 bool speed ATTRIBUTE_UNUSED)
863 enum machine_mode mode = GET_MODE (x);
865 switch (code)
867 case MEM:
869 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
870 if (simple_memory_operand (x, mode))
871 *total = COSTS_N_INSNS (2 * num_words);
872 else
873 *total = COSTS_N_INSNS (2 * (2 * num_words));
875 return true;
877 case NOT:
879 if (mode == DImode)
881 *total = COSTS_N_INSNS (2);
883 else
884 *total = COSTS_N_INSNS (1);
885 return false;
887 case AND:
888 case IOR:
889 case XOR:
891 if (mode == DImode)
893 *total = COSTS_N_INSNS (2);
895 else
896 *total = COSTS_N_INSNS (1);
898 return false;
900 case ASHIFT:
901 case ASHIFTRT:
902 case LSHIFTRT:
904 if (TARGET_BARREL_SHIFT)
906 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
907 >= 0)
908 *total = COSTS_N_INSNS (1);
909 else
910 *total = COSTS_N_INSNS (2);
912 else if (!TARGET_SOFT_MUL)
913 *total = COSTS_N_INSNS (1);
914 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
916 /* Add 1 to make shift slightly more expensive than add. */
917 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
918 /* Reduce shift costs for for special circumstances. */
919 if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
920 *total -= 2;
921 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
922 *total -= 2;
924 else
925 /* Double the worst cost of shifts when there is no barrel shifter and
926 the shift amount is in a reg. */
927 *total = COSTS_N_INSNS (32 * 4);
928 return true;
930 case PLUS:
931 case MINUS:
933 if (mode == SFmode || mode == DFmode)
935 if (TARGET_HARD_FLOAT)
936 *total = COSTS_N_INSNS (6);
937 return true;
939 else if (mode == DImode)
941 *total = COSTS_N_INSNS (4);
942 return true;
944 else
946 *total = COSTS_N_INSNS (1);
947 return true;
950 return false;
952 case NEG:
954 if (mode == DImode)
955 *total = COSTS_N_INSNS (4);
957 return false;
959 case MULT:
961 if (mode == SFmode)
963 if (TARGET_HARD_FLOAT)
964 *total = COSTS_N_INSNS (6);
966 else if (!TARGET_SOFT_MUL)
968 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
969 >= 0)
970 *total = COSTS_N_INSNS (1);
971 else
972 *total = COSTS_N_INSNS (3);
974 else
975 *total = COSTS_N_INSNS (10);
976 return true;
978 case DIV:
979 case UDIV:
981 if (mode == SFmode)
983 if (TARGET_HARD_FLOAT)
984 *total = COSTS_N_INSNS (23);
986 return false;
988 case SIGN_EXTEND:
990 *total = COSTS_N_INSNS (1);
991 return false;
993 case ZERO_EXTEND:
995 *total = COSTS_N_INSNS (1);
996 return false;
1000 return false;
1003 /* Return the number of instructions needed to load or store a value
1004 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1006 static int
1007 microblaze_address_insns (rtx x, enum machine_mode mode)
1009 struct microblaze_address_info addr;
1011 if (microblaze_classify_address (&addr, x, mode, false))
1013 switch (addr.type)
1015 case ADDRESS_REG:
1016 if (SMALL_INT (addr.offset))
1017 return 1;
1018 else
1019 return 2;
1020 case ADDRESS_CONST_INT:
1021 if (SMALL_INT (x))
1022 return 1;
1023 else
1024 return 2;
1025 case ADDRESS_REG_INDEX:
1026 case ADDRESS_SYMBOLIC:
1027 return 1;
1028 case ADDRESS_GOTOFF:
1029 return 2;
1030 default:
1031 break;
1034 return 0;
1037 /* Provide the costs of an addressing mode that contains ADDR.
1038 If ADDR is not a valid address, its cost is irrelevant. */
1039 static int
1040 microblaze_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
1042 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1045 /* Return nonzero if X is an address which needs a temporary register when
1046 reloaded while generating PIC code. */
1049 pic_address_needs_scratch (rtx x)
1051 /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
1052 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
1053 && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
1054 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
1055 && (flag_pic == 2 || !SMALL_INT (XEXP (XEXP (x, 0), 1))))
1056 return 1;
1058 return 0;
1061 /* Argument support functions. */
1062 /* Initialize CUMULATIVE_ARGS for a function. */
1064 void
1065 init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1066 rtx libname ATTRIBUTE_UNUSED)
1068 static CUMULATIVE_ARGS zero_cum;
1069 tree param, next_param;
1071 *cum = zero_cum;
1073 /* Determine if this function has variable arguments. This is
1074 indicated by the last argument being 'void_type_mode' if there
1075 are no variable arguments. The standard MicroBlaze calling sequence
1076 passes all arguments in the general purpose registers in this case. */
1078 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1079 param != 0; param = next_param)
1081 next_param = TREE_CHAIN (param);
1082 if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1083 cum->gp_reg_found = 1;
1087 /* Advance the argument to the next argument position. */
1089 static void
1090 microblaze_function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode,
1091 const_tree type, bool named ATTRIBUTE_UNUSED)
1093 cum->arg_number++;
1094 switch (mode)
1096 case VOIDmode:
1097 break;
1099 default:
1100 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1101 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1103 cum->gp_reg_found = 1;
1104 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1105 / UNITS_PER_WORD);
1106 break;
1108 case BLKmode:
1109 cum->gp_reg_found = 1;
1110 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1111 / UNITS_PER_WORD);
1112 break;
1114 case SFmode:
1115 cum->arg_words++;
1116 if (!cum->gp_reg_found && cum->arg_number <= 2)
1117 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1118 break;
1120 case DFmode:
1121 cum->arg_words += 2;
1122 if (!cum->gp_reg_found && cum->arg_number <= 2)
1123 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1124 break;
1126 case DImode:
1127 cum->gp_reg_found = 1;
1128 cum->arg_words += 2;
1129 break;
1131 case QImode:
1132 case HImode:
1133 case SImode:
1134 case TImode:
1135 cum->gp_reg_found = 1;
1136 cum->arg_words++;
1137 break;
1141 /* Return an RTL expression containing the register for the given mode,
1142 or 0 if the argument is to be passed on the stack. */
1144 static rtx
1145 microblaze_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode,
1146 const_tree type ATTRIBUTE_UNUSED,
1147 bool named ATTRIBUTE_UNUSED)
1149 rtx ret;
1150 int regbase = -1;
1151 int *arg_words = &cum->arg_words;
1153 cum->last_arg_fp = 0;
1154 switch (mode)
1156 case SFmode:
1157 case DFmode:
1158 case VOIDmode:
1159 case QImode:
1160 case HImode:
1161 case SImode:
1162 case DImode:
1163 case TImode:
1164 regbase = GP_ARG_FIRST;
1165 break;
1166 default:
1167 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1168 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1169 /* Drops through. */
1170 case BLKmode:
1171 regbase = GP_ARG_FIRST;
1172 break;
1175 if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1176 ret = 0;
1177 else
1179 gcc_assert (regbase != -1);
1181 ret = gen_rtx_REG (mode, regbase + *arg_words);
1184 if (mode == VOIDmode)
1186 if (cum->num_adjusts > 0)
1187 ret = gen_rtx_PARALLEL ((enum machine_mode) cum->fp_code,
1188 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1191 return ret;
1194 /* Return number of bytes of argument to put in registers. */
1195 static int
1196 function_arg_partial_bytes (CUMULATIVE_ARGS * cum, enum machine_mode mode,
1197 tree type, bool named ATTRIBUTE_UNUSED)
1199 if ((mode == BLKmode
1200 || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1201 || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1202 && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1204 int words;
1205 if (mode == BLKmode)
1206 words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1207 / UNITS_PER_WORD);
1208 else
1209 words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1211 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1212 return 0; /* structure fits in registers */
1214 return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1217 else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1218 return UNITS_PER_WORD;
1220 return 0;
1223 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1224 for easier range comparison. */
1225 static int
1226 microblaze_version_to_int (const char *version)
1228 const char *p, *v;
1229 const char *tmpl = "vX.YY.Z";
1230 int iver = 0;
1232 p = version;
1233 v = tmpl;
1235 while (*v)
1237 if (*v == 'X')
1238 { /* Looking for major */
1239 if (!(*p >= '0' && *p <= '9'))
1240 return -1;
1241 iver += (int) (*p - '0');
1242 iver *= 10;
1244 else if (*v == 'Y')
1245 { /* Looking for minor */
1246 if (!(*p >= '0' && *p <= '9'))
1247 return -1;
1248 iver += (int) (*p - '0');
1249 iver *= 10;
1251 else if (*v == 'Z')
1252 { /* Looking for compat */
1253 if (!(*p >= 'a' && *p <= 'z'))
1254 return -1;
1255 iver *= 10;
1256 iver += (int) (*p - 'a');
1258 else
1260 if (*p != *v)
1261 return -1;
1264 v++;
1265 p++;
1268 if (*p)
1269 return -1;
1271 return iver;
1274 static bool
1275 microblaze_handle_option (size_t code,
1276 const char *arg ATTRIBUTE_UNUSED,
1277 int value ATTRIBUTE_UNUSED)
1279 switch (code)
1281 case OPT_mno_clearbss:
1282 flag_zero_initialized_in_bss = 0;
1283 warning (0, "-mno-clearbss is deprecated; use -fno-zero-initialized-in-bss");
1284 break;
1285 case OPT_mxl_stack_check:
1286 warning (0, "-mxl_stack_check is deprecated; use -fstack-check");
1287 break;
1289 return true;
1293 static void
1294 microblaze_option_override (void)
1296 register int i, start;
1297 register int regno;
1298 register enum machine_mode mode;
1299 int ver;
1301 microblaze_section_threshold = (global_options_set.x_g_switch_value
1302 ? g_switch_value
1303 : MICROBLAZE_DEFAULT_GVALUE);
1305 /* Check the MicroBlaze CPU version for any special action to be done. */
1306 if (microblaze_select_cpu == NULL)
1307 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1308 ver = microblaze_version_to_int (microblaze_select_cpu);
1309 if (ver == -1)
1311 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu);
1314 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1315 if (ver < 0)
1317 /* No hardware exceptions in earlier versions. So no worries. */
1318 #if 0
1319 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1320 #endif
1321 microblaze_no_unsafe_delay = 0;
1322 microblaze_pipe = MICROBLAZE_PIPE_3;
1324 else if (ver == 0
1325 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1326 == 0))
1328 #if 0
1329 microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1330 #endif
1331 microblaze_no_unsafe_delay = 1;
1332 microblaze_pipe = MICROBLAZE_PIPE_3;
1334 else
1336 /* We agree to use 5 pipe-stage model even on area optimized 3
1337 pipe-stage variants. */
1338 #if 0
1339 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1340 #endif
1341 microblaze_no_unsafe_delay = 0;
1342 microblaze_pipe = MICROBLAZE_PIPE_5;
1343 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1344 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1345 "v5.00.b") == 0
1346 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1347 "v5.00.c") == 0)
1349 /* Pattern compares are to be turned on by default only when
1350 compiling for MB v5.00.'z'. */
1351 target_flags |= MASK_PATTERN_COMPARE;
1355 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1356 if (ver < 0)
1358 if (TARGET_MULTIPLY_HIGH)
1359 warning (0,
1360 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1363 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1364 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1366 /* Always use DFA scheduler. */
1367 microblaze_sched_use_dfa = 1;
1369 #if 0
1370 microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1371 #endif
1373 /* Initialize the high, low values for legit floating point constants. */
1374 real_maxval (&dfhigh, 0, DFmode);
1375 real_maxval (&dflow, 1, DFmode);
1376 real_maxval (&sfhigh, 0, SFmode);
1377 real_maxval (&sflow, 1, SFmode);
1379 microblaze_print_operand_punct['?'] = 1;
1380 microblaze_print_operand_punct['#'] = 1;
1381 microblaze_print_operand_punct['&'] = 1;
1382 microblaze_print_operand_punct['!'] = 1;
1383 microblaze_print_operand_punct['*'] = 1;
1384 microblaze_print_operand_punct['@'] = 1;
1385 microblaze_print_operand_punct['.'] = 1;
1386 microblaze_print_operand_punct['('] = 1;
1387 microblaze_print_operand_punct[')'] = 1;
1388 microblaze_print_operand_punct['['] = 1;
1389 microblaze_print_operand_punct[']'] = 1;
1390 microblaze_print_operand_punct['<'] = 1;
1391 microblaze_print_operand_punct['>'] = 1;
1392 microblaze_print_operand_punct['{'] = 1;
1393 microblaze_print_operand_punct['}'] = 1;
1394 microblaze_print_operand_punct['^'] = 1;
1395 microblaze_print_operand_punct['$'] = 1;
1396 microblaze_print_operand_punct['+'] = 1;
1398 /* Set up array to map GCC register number to debug register number.
1399 Ignore the special purpose register numbers. */
1401 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1402 microblaze_dbx_regno[i] = -1;
1404 start = GP_DBX_FIRST - GP_REG_FIRST;
1405 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1406 microblaze_dbx_regno[i] = i + start;
1408 /* Set up array giving whether a given register can hold a given mode. */
1410 for (mode = VOIDmode;
1411 mode != MAX_MACHINE_MODE; mode = (enum machine_mode) ((int) mode + 1))
1413 register int size = GET_MODE_SIZE (mode);
1415 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1417 register int ok;
1419 if (mode == CCmode)
1421 ok = (ST_REG_P (regno) || GP_REG_P (regno));
1423 else if (GP_REG_P (regno))
1424 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1425 else
1426 ok = 0;
1428 microblaze_hard_regno_mode_ok[(int) mode][regno] = ok;
1433 /* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
1434 static const struct default_options microblaze_option_optimization_table[] =
1436 { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
1437 { OPT_LEVELS_NONE, 0, NULL, 0 }
1440 /* Return true if FUNC is an interrupt function as specified
1441 by the "interrupt_handler" attribute. */
1443 static int
1444 microblaze_interrupt_function_p (tree func)
1446 tree a;
1448 if (TREE_CODE (func) != FUNCTION_DECL)
1449 return 0;
1451 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1452 return a != NULL_TREE;
1455 /* Return true if FUNC is an interrupt function which uses
1456 normal return, indicated by the "save_volatiles" attribute. */
1458 static int
1459 microblaze_save_volatiles (tree func)
1461 tree a;
1463 if (TREE_CODE (func) != FUNCTION_DECL)
1464 return 0;
1466 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1467 return a != NULL_TREE;
1470 /* Return whether function is tagged with 'interrupt_handler'
1471 attribute. Return true if function should use return from
1472 interrupt rather than normal function return. */
1474 microblaze_is_interrupt_handler (void)
1476 return interrupt_handler;
1479 /* Determine of register must be saved/restored in call. */
1480 static int
1481 microblaze_must_save_register (int regno)
1483 if (pic_offset_table_rtx &&
1484 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
1485 return 1;
1487 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1488 return 1;
1490 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1491 return 1;
1493 if (!current_function_is_leaf)
1495 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1496 return 1;
1497 if ((interrupt_handler || save_volatiles) &&
1498 (regno >= 3 && regno <= 12))
1499 return 1;
1502 if (interrupt_handler)
1504 if (df_regs_ever_live_p (regno)
1505 || regno == MB_ABI_MSR_SAVE_REG
1506 || regno == MB_ABI_ASM_TEMP_REGNUM
1507 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1508 return 1;
1511 if (save_volatiles)
1513 if (df_regs_ever_live_p (regno)
1514 || regno == MB_ABI_ASM_TEMP_REGNUM
1515 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1516 return 1;
1519 return 0;
1522 /* Return the bytes needed to compute the frame pointer from the current
1523 stack pointer.
1525 MicroBlaze stack frames look like:
1529 Before call After call
1530 +-----------------------+ +-----------------------+
1531 high | | | |
1532 mem. | local variables, | | local variables, |
1533 | callee saved and | | callee saved and |
1534 | temps | | temps |
1535 +-----------------------+ +-----------------------+
1536 | arguments for called | | arguments for called |
1537 | subroutines | | subroutines |
1538 | (optional) | | (optional) |
1539 +-----------------------+ +-----------------------+
1540 | Link register | | Link register |
1541 SP->| | | |
1542 +-----------------------+ +-----------------------+
1544 | local variables, |
1545 | callee saved and |
1546 | temps |
1547 +-----------------------+
1548 | MSR (optional if, |
1549 | interrupt handler) |
1550 +-----------------------+
1552 | alloca allocations |
1554 +-----------------------+
1556 | arguments for called |
1557 | subroutines |
1558 | (optional) |
1560 +-----------------------+
1561 | Link register |
1562 low FP,SP->| |
1563 memory +-----------------------+
1567 static HOST_WIDE_INT
1568 compute_frame_size (HOST_WIDE_INT size)
1570 int regno;
1571 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
1572 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
1573 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
1574 int link_debug_size; /* # bytes for link register. */
1575 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
1576 long mask; /* mask of saved gp registers. */
1578 interrupt_handler =
1579 microblaze_interrupt_function_p (current_function_decl);
1580 save_volatiles = microblaze_save_volatiles (current_function_decl);
1582 gp_reg_size = 0;
1583 mask = 0;
1584 var_size = size;
1585 args_size = crtl->outgoing_args_size;
1587 if ((args_size == 0) && cfun->calls_alloca)
1588 args_size = NUM_OF_ARGS * UNITS_PER_WORD;
1590 total_size = var_size + args_size;
1592 if (flag_pic == 2)
1593 /* force setting GOT. */
1594 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
1596 /* Calculate space needed for gp registers. */
1597 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
1599 if (microblaze_must_save_register (regno))
1602 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
1603 /* Don't account for link register. It is accounted specially below. */
1604 gp_reg_size += GET_MODE_SIZE (SImode);
1606 mask |= (1L << (regno - GP_REG_FIRST));
1610 total_size += gp_reg_size;
1612 /* Add 4 bytes for MSR. */
1613 if (interrupt_handler)
1614 total_size += 4;
1616 /* No space to be allocated for link register in leaf functions with no other
1617 stack requirements. */
1618 if (total_size == 0 && current_function_is_leaf)
1619 link_debug_size = 0;
1620 else
1621 link_debug_size = UNITS_PER_WORD;
1623 total_size += link_debug_size;
1625 /* Save other computed information. */
1626 current_frame_info.total_size = total_size;
1627 current_frame_info.var_size = var_size;
1628 current_frame_info.args_size = args_size;
1629 current_frame_info.gp_reg_size = gp_reg_size;
1630 current_frame_info.mask = mask;
1631 current_frame_info.initialized = reload_completed;
1632 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
1633 current_frame_info.link_debug_size = link_debug_size;
1635 if (mask)
1636 /* Offset from which to callee-save GP regs. */
1637 current_frame_info.gp_offset = (total_size - gp_reg_size);
1638 else
1639 current_frame_info.gp_offset = 0;
1641 /* Ok, we're done. */
1642 return total_size;
1645 /* Make sure that we're not trying to eliminate to the wrong hard frame
1646 pointer. */
1648 static bool
1649 microblaze_can_eliminate (const int from, const int to)
1651 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
1652 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
1653 || (from != RETURN_ADDRESS_POINTER_REGNUM
1654 && (to == HARD_FRAME_POINTER_REGNUM
1655 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
1658 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
1659 pointer or argument pointer or the return address pointer. TO is either
1660 the stack pointer or hard frame pointer. */
1662 HOST_WIDE_INT
1663 microblaze_initial_elimination_offset (int from, int to)
1665 HOST_WIDE_INT offset;
1667 switch (from)
1669 case FRAME_POINTER_REGNUM:
1670 offset = 0;
1671 break;
1672 case ARG_POINTER_REGNUM:
1673 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
1674 offset = compute_frame_size (get_frame_size ());
1675 else
1676 gcc_unreachable ();
1677 break;
1678 case RETURN_ADDRESS_POINTER_REGNUM:
1679 if (current_function_is_leaf)
1680 offset = 0;
1681 else
1682 offset = current_frame_info.gp_offset +
1683 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
1684 break;
1685 default:
1686 gcc_unreachable ();
1688 return offset;
1691 /* Print operands using format code.
1693 The MicroBlaze specific codes are:
1695 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
1696 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
1697 'F' op is CONST_DOUBLE, print 32 bits in hex,
1698 'd' output integer constant in decimal,
1699 'z' if the operand is 0, use $0 instead of normal operand.
1700 'D' print second register of double-word register operand.
1701 'L' print low-order register of double-word register operand.
1702 'M' print high-order register of double-word register operand.
1703 'C' print part of opcode for a branch condition.
1704 'N' print part of opcode for a branch condition, inverted.
1705 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
1706 'B' print 'z' for EQ, 'n' for NE
1707 'b' print 'n' for EQ, 'z' for NE
1708 'T' print 'f' for EQ, 't' for NE
1709 't' print 't' for EQ, 'f' for NE
1710 'm' Print 1<<operand.
1711 'i' Print 'i' if MEM operand has immediate value
1712 'o' Print operand address+4
1713 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
1714 'h' Print high word of const_double (int or float) value as hex
1715 'j' Print low word of const_double (int or float) value as hex
1716 's' Print -1 if operand is negative, 0 if positive (sign extend)
1717 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
1718 '#' Print nop if the delay slot of a branch is not filled.
1721 void
1722 print_operand (FILE * file, rtx op, int letter)
1724 register enum rtx_code code;
1726 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
1728 switch (letter)
1730 case '?':
1731 /* Conditionally add a 'd' to indicate filled delay slot. */
1732 if (final_sequence != NULL)
1733 fputs ("d", file);
1734 break;
1736 case '#':
1737 /* Conditionally add a nop in unfilled delay slot. */
1738 if (final_sequence == NULL)
1739 fputs ("nop\t\t# Unfilled delay slot\n", file);
1740 break;
1742 case '@':
1743 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
1744 break;
1746 default:
1747 output_operand_lossage ("unknown punctuation '%c'", letter);
1748 break;
1751 return;
1754 if (!op)
1756 output_operand_lossage ("null pointer");
1757 return;
1760 code = GET_CODE (op);
1762 if (code == SIGN_EXTEND)
1763 op = XEXP (op, 0), code = GET_CODE (op);
1765 if (letter == 'C')
1766 switch (code)
1768 case EQ:
1769 fputs ("eq", file);
1770 break;
1771 case NE:
1772 fputs ("ne", file);
1773 break;
1774 case GT:
1775 case GTU:
1776 fputs ("gt", file);
1777 break;
1778 case GE:
1779 case GEU:
1780 fputs ("ge", file);
1781 break;
1782 case LT:
1783 case LTU:
1784 fputs ("lt", file);
1785 break;
1786 case LE:
1787 case LEU:
1788 fputs ("le", file);
1789 break;
1790 default:
1791 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
1794 else if (letter == 'N')
1795 switch (code)
1797 case EQ:
1798 fputs ("ne", file);
1799 break;
1800 case NE:
1801 fputs ("eq", file);
1802 break;
1803 case GT:
1804 case GTU:
1805 fputs ("le", file);
1806 break;
1807 case GE:
1808 case GEU:
1809 fputs ("lt", file);
1810 break;
1811 case LT:
1812 case LTU:
1813 fputs ("ge", file);
1814 break;
1815 case LE:
1816 case LEU:
1817 fputs ("gt", file);
1818 break;
1819 default:
1820 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
1823 else if (letter == 'S')
1825 char buffer[100];
1827 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
1828 assemble_name (file, buffer);
1831 /* Print 'i' for memory operands which have immediate values. */
1832 else if (letter == 'i')
1834 if (code == MEM)
1836 struct microblaze_address_info info;
1838 if (!microblaze_classify_address
1839 (&info, XEXP (op, 0), GET_MODE (op), 1))
1840 fatal_insn ("insn contains an invalid address !", op);
1842 switch (info.type)
1844 case ADDRESS_REG:
1845 case ADDRESS_CONST_INT:
1846 case ADDRESS_SYMBOLIC:
1847 case ADDRESS_GOTOFF:
1848 fputs ("i", file);
1849 break;
1850 case ADDRESS_REG_INDEX:
1851 break;
1852 case ADDRESS_INVALID:
1853 case ADDRESS_PLT:
1854 fatal_insn ("invalid address", op);
1859 else if (code == REG || code == SUBREG)
1861 register int regnum;
1863 if (code == REG)
1864 regnum = REGNO (op);
1865 else
1866 regnum = true_regnum (op);
1868 if ((letter == 'M' && !WORDS_BIG_ENDIAN)
1869 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
1870 regnum++;
1872 fprintf (file, "%s", reg_names[regnum]);
1875 else if (code == MEM)
1876 if (letter == 'o')
1878 rtx op4 = adjust_address (op, GET_MODE (op), 4);
1879 output_address (XEXP (op4, 0));
1881 else
1882 output_address (XEXP (op, 0));
1884 else if (letter == 'h' || letter == 'j')
1886 long val[2];
1887 if (code == CONST_DOUBLE)
1889 if (GET_MODE (op) == DFmode)
1891 REAL_VALUE_TYPE value;
1892 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
1893 REAL_VALUE_TO_TARGET_DOUBLE (value, val);
1895 else
1897 val[0] = CONST_DOUBLE_HIGH (op);
1898 val[1] = CONST_DOUBLE_LOW (op);
1901 else if (code == CONST_INT)
1903 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
1904 val[1] = INTVAL (op) & 0x00000000ffffffffLL;
1905 if (val[0] == 0 && val[1] < 0)
1906 val[0] = -1;
1909 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
1911 else if (code == CONST_DOUBLE)
1913 if (letter == 'F')
1915 unsigned long value_long;
1916 REAL_VALUE_TYPE value;
1917 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
1918 REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
1919 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
1921 else
1923 char s[60];
1924 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
1925 fputs (s, file);
1929 else if (code == UNSPEC)
1931 print_operand_address (file, op);
1934 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
1935 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
1937 else if (letter == 'X' && GET_CODE (op) == CONST_INT)
1938 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
1940 else if (letter == 'd' && GET_CODE (op) == CONST_INT)
1941 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
1943 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
1944 fputs (reg_names[GP_REG_FIRST], file);
1946 else if (letter == 's' && GET_CODE (op) == CONST_INT)
1947 if (INTVAL (op) < 0)
1948 fputs ("-1", file);
1949 else
1950 fputs ("0", file);
1952 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
1953 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
1955 else if (letter == 'B')
1956 fputs (code == EQ ? "z" : "n", file);
1957 else if (letter == 'b')
1958 fputs (code == EQ ? "n" : "z", file);
1959 else if (letter == 'T')
1960 fputs (code == EQ ? "f" : "t", file);
1961 else if (letter == 't')
1962 fputs (code == EQ ? "t" : "f", file);
1964 else if (code == CONST && GET_CODE (XEXP (op, 0)) == REG)
1966 print_operand (file, XEXP (op, 0), letter);
1968 else if (letter == 'm')
1969 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
1970 else
1971 output_addr_const (file, op);
1974 /* A C compound statement to output to stdio stream STREAM the
1975 assembler syntax for an instruction operand that is a memory
1976 reference whose address is ADDR. ADDR is an RTL expression.
1978 Possible address classifications and output formats are,
1980 ADDRESS_REG "%0, r0"
1982 ADDRESS_REG with non-zero "%0, <addr_const>"
1983 offset
1985 ADDRESS_REG_INDEX "rA, RB"
1986 (if rA is r0, rA and rB are swapped)
1988 ADDRESS_CONST_INT "r0, <addr_const>"
1990 ADDRESS_SYMBOLIC "rBase, <addr_const>"
1991 (rBase is a base register suitable for the
1992 symbol's type)
1995 void
1996 print_operand_address (FILE * file, rtx addr)
1998 struct microblaze_address_info info;
1999 enum microblaze_address_type type;
2000 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
2001 fatal_insn ("insn contains an invalid address !", addr);
2003 type = info.type;
2004 switch (info.type)
2006 case ADDRESS_REG:
2007 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2008 output_addr_const (file, info.offset);
2009 break;
2010 case ADDRESS_REG_INDEX:
2011 if (REGNO (info.regA) == 0)
2012 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2013 congestion. */
2014 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2015 reg_names[REGNO (info.regA)]);
2016 else if (REGNO (info.regB) != 0)
2017 /* This is a silly swap to help Dhrystone. */
2018 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2019 reg_names[REGNO (info.regA)]);
2020 break;
2021 case ADDRESS_CONST_INT:
2022 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2023 output_addr_const (file, info.offset);
2024 break;
2025 case ADDRESS_SYMBOLIC:
2026 case ADDRESS_GOTOFF:
2027 case ADDRESS_PLT:
2028 if (info.regA)
2029 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2030 output_addr_const (file, info.symbol);
2031 if (type == ADDRESS_GOTOFF)
2033 fputs ("@GOT", file);
2035 else if (type == ADDRESS_PLT)
2037 fputs ("@PLT", file);
2039 break;
2040 case ADDRESS_INVALID:
2041 fatal_insn ("invalid address", addr);
2042 break;
2046 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2047 is used, so that we don't emit an .extern for it in
2048 microblaze_asm_file_end. */
2050 void
2051 microblaze_declare_object (FILE * stream, const char *name,
2052 const char *section, const char *fmt, int size)
2055 fputs (section, stream);
2056 assemble_name (stream, name);
2057 fprintf (stream, fmt, size);
2060 /* Common code to emit the insns (or to write the instructions to a file)
2061 to save/restore registers.
2063 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2064 is not modified within save_restore_insns. */
2066 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2068 /* Save or restore instructions based on whether this is the prologue or
2069 epilogue. prologue is 1 for the prologue. */
2070 static void
2071 save_restore_insns (int prologue)
2073 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2074 0, isr_mem_rtx = 0;
2075 rtx isr_msr_rtx = 0, insn;
2076 long mask = current_frame_info.mask;
2077 HOST_WIDE_INT gp_offset;
2078 int regno;
2080 if (frame_pointer_needed
2081 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2082 gcc_unreachable ();
2084 if (mask == 0)
2085 return;
2087 /* Save registers starting from high to low. The debuggers prefer at least
2088 the return register be stored at func+4, and also it allows us not to
2089 need a nop in the epilog if at least one register is reloaded in
2090 addition to return address. */
2092 /* Pick which pointer to use as a base register. For small frames, just
2093 use the stack pointer. Otherwise, use a temporary register. Save 2
2094 cycles if the save area is near the end of a large frame, by reusing
2095 the constant created in the prologue/epilogue to adjust the stack
2096 frame. */
2098 gp_offset = current_frame_info.gp_offset;
2100 gcc_assert (gp_offset > 0);
2102 base_reg_rtx = stack_pointer_rtx;
2104 /* For interrupt_handlers, need to save/restore the MSR. */
2105 if (interrupt_handler)
2107 isr_mem_rtx = gen_rtx_MEM (SImode,
2108 gen_rtx_PLUS (Pmode, base_reg_rtx,
2109 GEN_INT (current_frame_info.
2110 gp_offset -
2111 UNITS_PER_WORD)));
2113 /* Do not optimize in flow analysis. */
2114 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2115 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2116 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2119 if (interrupt_handler && !prologue)
2121 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2122 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2123 /* Do not optimize in flow analysis. */
2124 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2125 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2128 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2130 if (BITSET_P (mask, regno - GP_REG_FIRST))
2132 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2133 /* Don't handle here. Already handled as the first register. */
2134 continue;
2136 reg_rtx = gen_rtx_REG (SImode, regno);
2137 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2138 mem_rtx = gen_rtx_MEM (SImode, insn);
2139 if (interrupt_handler || save_volatiles)
2140 /* Do not optimize in flow analysis. */
2141 MEM_VOLATILE_P (mem_rtx) = 1;
2143 if (prologue)
2145 insn = emit_move_insn (mem_rtx, reg_rtx);
2146 RTX_FRAME_RELATED_P (insn) = 1;
2148 else
2150 insn = emit_move_insn (reg_rtx, mem_rtx);
2153 gp_offset += GET_MODE_SIZE (SImode);
2157 if (interrupt_handler && prologue)
2159 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2160 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2162 /* Do not optimize in flow analysis. */
2163 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2164 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2167 /* Done saving and restoring */
2171 /* Set up the stack and frame (if desired) for the function. */
2172 static void
2173 microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2175 const char *fnname;
2176 long fsiz = current_frame_info.total_size;
2178 /* Get the function name the same way that toplev.c does before calling
2179 assemble_start_function. This is needed so that the name used here
2180 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2181 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2182 if (!flag_inhibit_size_directive)
2184 fputs ("\t.ent\t", file);
2185 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2186 fputs ("_interrupt_handler", file);
2187 else
2188 assemble_name (file, fnname);
2189 fputs ("\n", file);
2190 if (!interrupt_handler)
2191 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2194 assemble_name (file, fnname);
2195 fputs (":\n", file);
2197 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2198 fputs ("_interrupt_handler:\n", file);
2200 if (!flag_inhibit_size_directive)
2202 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2203 fprintf (file,
2204 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2205 (reg_names[(frame_pointer_needed)
2206 ? HARD_FRAME_POINTER_REGNUM :
2207 STACK_POINTER_REGNUM]), fsiz,
2208 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2209 current_frame_info.var_size, current_frame_info.num_gp,
2210 crtl->outgoing_args_size);
2211 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2215 /* Output extra assembler code at the end of a prologue. */
2216 static void
2217 microblaze_function_end_prologue (FILE * file)
2219 if (TARGET_STACK_CHECK)
2221 fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2222 fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2223 fprintf (file, "cmpu\tr18,r1,r18\n\t");
2224 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2225 fprintf (file, "# Stack Check Stub -- End.\n");
2229 /* Expand the prologue into a bunch of separate insns. */
2231 void
2232 microblaze_expand_prologue (void)
2234 int regno;
2235 HOST_WIDE_INT fsiz;
2236 const char *arg_name = 0;
2237 tree fndecl = current_function_decl;
2238 tree fntype = TREE_TYPE (fndecl);
2239 tree fnargs = DECL_ARGUMENTS (fndecl);
2240 rtx next_arg_reg;
2241 int i;
2242 tree next_arg;
2243 tree cur_arg;
2244 CUMULATIVE_ARGS args_so_far;
2245 rtx mem_rtx, reg_rtx;
2247 /* If struct value address is treated as the first argument, make it so. */
2248 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2249 && !cfun->returns_pcc_struct)
2251 tree type = build_pointer_type (fntype);
2252 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2253 NULL_TREE, type);
2255 DECL_ARG_TYPE (function_result_decl) = type;
2256 TREE_CHAIN (function_result_decl) = fnargs;
2257 fnargs = function_result_decl;
2260 /* Determine the last argument, and get its name. */
2262 INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0, 0);
2263 regno = GP_ARG_FIRST;
2265 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2267 tree passed_type = DECL_ARG_TYPE (cur_arg);
2268 enum machine_mode passed_mode = TYPE_MODE (passed_type);
2269 rtx entry_parm;
2271 if (TREE_ADDRESSABLE (passed_type))
2273 passed_type = build_pointer_type (passed_type);
2274 passed_mode = Pmode;
2277 entry_parm = targetm.calls.function_arg (&args_so_far, passed_mode,
2278 passed_type, true);
2280 if (entry_parm)
2282 int words;
2284 /* passed in a register, so will get homed automatically. */
2285 if (GET_MODE (entry_parm) == BLKmode)
2286 words = (int_size_in_bytes (passed_type) + 3) / 4;
2287 else
2288 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2290 regno = REGNO (entry_parm) + words - 1;
2292 else
2294 regno = GP_ARG_LAST + 1;
2295 break;
2298 targetm.calls.function_arg_advance (&args_so_far, passed_mode,
2299 passed_type, true);
2301 next_arg = TREE_CHAIN (cur_arg);
2302 if (next_arg == 0)
2304 if (DECL_NAME (cur_arg))
2305 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2307 break;
2311 /* Split parallel insn into a sequence of insns. */
2313 next_arg_reg = targetm.calls.function_arg (&args_so_far, VOIDmode,
2314 void_type_node, true);
2315 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2317 rtvec adjust = XVEC (next_arg_reg, 0);
2318 int num = GET_NUM_ELEM (adjust);
2320 for (i = 0; i < num; i++)
2322 rtx pattern = RTVEC_ELT (adjust, i);
2323 emit_insn (pattern);
2327 fsiz = compute_frame_size (get_frame_size ());
2329 /* If this function is a varargs function, store any registers that
2330 would normally hold arguments ($5 - $10) on the stack. */
2331 if (((TYPE_ARG_TYPES (fntype) != 0
2332 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2333 != void_type_node))
2334 || (arg_name != 0
2335 && ((arg_name[0] == '_'
2336 && strcmp (arg_name, "__builtin_va_alist") == 0)
2337 || (arg_name[0] == 'v'
2338 && strcmp (arg_name, "va_alist") == 0)))))
2340 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2341 rtx ptr = stack_pointer_rtx;
2343 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2344 for (; regno <= GP_ARG_LAST; regno++)
2346 if (offset != 0)
2347 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2348 emit_move_insn (gen_rtx_MEM (SImode, ptr),
2349 gen_rtx_REG (SImode, regno));
2351 offset += GET_MODE_SIZE (SImode);
2356 if (fsiz > 0)
2358 rtx fsiz_rtx = GEN_INT (fsiz);
2360 rtx insn = NULL;
2361 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2362 fsiz_rtx));
2363 if (insn)
2364 RTX_FRAME_RELATED_P (insn) = 1;
2366 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2367 if (!current_function_is_leaf || interrupt_handler)
2369 mem_rtx = gen_rtx_MEM (SImode,
2370 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2371 const0_rtx));
2373 if (interrupt_handler)
2374 /* Do not optimize in flow analysis. */
2375 MEM_VOLATILE_P (mem_rtx) = 1;
2377 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2378 insn = emit_move_insn (mem_rtx, reg_rtx);
2379 RTX_FRAME_RELATED_P (insn) = 1;
2382 /* _save_ registers for prologue. */
2383 save_restore_insns (1);
2385 if (frame_pointer_needed)
2387 rtx insn = 0;
2389 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2390 stack_pointer_rtx));
2392 if (insn)
2393 RTX_FRAME_RELATED_P (insn) = 1;
2397 if (flag_pic == 2 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
2399 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
2400 emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
2403 /* If we are profiling, make sure no instructions are scheduled before
2404 the call to mcount. */
2406 if (profile_flag)
2407 emit_insn (gen_blockage ());
2410 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2412 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2413 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2415 static void
2416 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
2417 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2419 const char *fnname;
2421 /* Get the function name the same way that toplev.c does before calling
2422 assemble_start_function. This is needed so that the name used here
2423 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2424 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2426 if (!flag_inhibit_size_directive)
2428 fputs ("\t.end\t", file);
2429 if (interrupt_handler)
2430 fputs ("_interrupt_handler", file);
2431 else
2432 assemble_name (file, fnname);
2433 fputs ("\n", file);
2436 /* Reset state info for each function. */
2437 current_frame_info = zero_frame_info;
2439 /* Restore the output file if optimizing the GP (optimizing the GP causes
2440 the text to be diverted to a tempfile, so that data decls come before
2441 references to the data). */
2444 /* Expand the epilogue into a bunch of separate insns. */
2446 void
2447 microblaze_expand_epilogue (void)
2449 HOST_WIDE_INT fsiz = current_frame_info.total_size;
2450 rtx fsiz_rtx = GEN_INT (fsiz);
2451 rtx reg_rtx;
2452 rtx mem_rtx;
2454 /* In case of interrupt handlers use addki instead of addi for changing the
2455 stack pointer value. */
2457 if (microblaze_can_use_return_insn ())
2459 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
2460 GP_REG_FIRST +
2461 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2462 return;
2465 if (fsiz > 0)
2467 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
2468 sequence of load-followed by a use (in rtsd) in every prologue. Saves
2469 a load-use stall cycle :) This is also important to handle alloca.
2470 (See comments for if (frame_pointer_needed) below. */
2472 if (!current_function_is_leaf || interrupt_handler)
2474 mem_rtx =
2475 gen_rtx_MEM (SImode,
2476 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
2477 if (interrupt_handler)
2478 /* Do not optimize in flow analysis. */
2479 MEM_VOLATILE_P (mem_rtx) = 1;
2480 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2481 emit_move_insn (reg_rtx, mem_rtx);
2484 /* It is important that this is done after we restore the return address
2485 register (above). When alloca is used, we want to restore the
2486 sub-routine return address only from the current stack top and not
2487 from the frame pointer (which we restore below). (frame_pointer + 0)
2488 might have been over-written since alloca allocates memory on the
2489 current stack. */
2490 if (frame_pointer_needed)
2491 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
2493 /* _restore_ registers for epilogue. */
2494 save_restore_insns (0);
2495 emit_insn (gen_blockage ());
2496 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
2499 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
2500 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2504 /* Return nonzero if this function is known to have a null epilogue.
2505 This allows the optimizer to omit jumps to jumps if no stack
2506 was created. */
2509 microblaze_can_use_return_insn (void)
2511 if (!reload_completed)
2512 return 0;
2514 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
2515 return 0;
2517 if (current_frame_info.initialized)
2518 return current_frame_info.total_size == 0;
2520 return compute_frame_size (get_frame_size ()) == 0;
2523 /* Implement TARGET_SECONDARY_RELOAD. */
2525 static reg_class_t
2526 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
2527 reg_class_t rclass, enum machine_mode mode ATTRIBUTE_UNUSED,
2528 secondary_reload_info *sri ATTRIBUTE_UNUSED)
2530 if (rclass == ST_REGS)
2531 return GR_REGS;
2533 return NO_REGS;
2536 static void
2537 microblaze_globalize_label (FILE * stream, const char *name)
2539 fputs ("\t.globl\t", stream);
2540 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
2542 fputs (INTERRUPT_HANDLER_NAME, stream);
2543 fputs ("\n\t.globl\t", stream);
2545 assemble_name (stream, name);
2546 fputs ("\n", stream);
2549 /* Returns true if decl should be placed into a "small data" section. */
2550 static bool
2551 microblaze_elf_in_small_data_p (const_tree decl)
2553 HOST_WIDE_INT size;
2555 if (!TARGET_XLGPOPT)
2556 return false;
2558 /* We want to merge strings, so we never consider them small data. */
2559 if (TREE_CODE (decl) == STRING_CST)
2560 return false;
2562 /* Functions are never in the small data area. */
2563 if (TREE_CODE (decl) == FUNCTION_DECL)
2564 return false;
2566 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
2568 const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
2569 if (strcmp (section, ".sdata") == 0
2570 || strcmp (section, ".sdata2") == 0
2571 || strcmp (section, ".sbss") == 0
2572 || strcmp (section, ".sbss2") == 0)
2573 return true;
2576 size = int_size_in_bytes (TREE_TYPE (decl));
2578 return (size > 0 && size <= microblaze_section_threshold);
2582 static section *
2583 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
2585 switch (categorize_decl_for_section (decl, reloc))
2587 case SECCAT_RODATA_MERGE_STR:
2588 case SECCAT_RODATA_MERGE_STR_INIT:
2589 /* MB binutils have various issues with mergeable string sections and
2590 relaxation/relocation. Currently, turning mergeable sections
2591 into regular readonly sections. */
2593 return readonly_data_section;
2594 default:
2595 return default_elf_select_section (decl, reloc, align);
2600 Encode info about sections into the RTL based on a symbol's declaration.
2601 The default definition of this hook, default_encode_section_info in
2602 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
2604 static void
2605 microblaze_encode_section_info (tree decl, rtx rtl, int first)
2607 default_encode_section_info (decl, rtl, first);
2610 static rtx
2611 expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED, rtx op)
2613 rtx result;
2614 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
2615 result = gen_rtx_CONST (Pmode, result);
2616 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
2617 result = gen_const_mem (Pmode, result);
2618 return result;
2621 bool
2622 microblaze_expand_move (enum machine_mode mode, rtx operands[])
2624 /* If operands[1] is a constant address invalid for pic, then we need to
2625 handle it just like LEGITIMIZE_ADDRESS does. */
2626 if (flag_pic)
2628 if (GET_CODE (operands[0]) == MEM)
2630 rtx addr = XEXP (operands[0], 0);
2631 if (GET_CODE (addr) == SYMBOL_REF)
2633 rtx ptr_reg, result;
2635 if (reload_in_progress)
2636 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2638 addr = expand_pic_symbol_ref (mode, addr);
2639 ptr_reg = gen_reg_rtx (Pmode);
2640 emit_move_insn (ptr_reg, addr);
2641 result = gen_rtx_MEM (mode, ptr_reg);
2642 operands[0] = result;
2645 if (GET_CODE (operands[1]) == SYMBOL_REF
2646 || GET_CODE (operands[1]) == LABEL_REF)
2648 rtx result;
2649 if (reload_in_progress)
2650 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2651 result = expand_pic_symbol_ref (mode, operands[1]);
2652 if (GET_CODE (operands[0]) != REG)
2654 rtx ptr_reg = gen_reg_rtx (Pmode);
2655 emit_move_insn (ptr_reg, result);
2656 emit_move_insn (operands[0], ptr_reg);
2658 else
2660 emit_move_insn (operands[0], result);
2662 return true;
2664 else if (GET_CODE (operands[1]) == MEM &&
2665 GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
2667 rtx result;
2668 rtx ptr_reg;
2669 if (reload_in_progress)
2670 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2671 result = expand_pic_symbol_ref (mode, XEXP (operands[1], 0));
2673 ptr_reg = gen_reg_rtx (Pmode);
2675 emit_move_insn (ptr_reg, result);
2676 result = gen_rtx_MEM (mode, ptr_reg);
2677 emit_move_insn (operands[0], result);
2678 return true;
2680 else if (pic_address_needs_scratch (operands[1]))
2682 rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0));
2683 rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
2685 if (reload_in_progress)
2686 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2687 emit_move_insn (operands[0], gen_rtx_PLUS (SImode, temp, temp2));
2688 return true;
2692 if ((reload_in_progress | reload_completed) == 0
2693 && !register_operand (operands[0], SImode)
2694 && !register_operand (operands[1], SImode)
2695 && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
2697 rtx temp = force_reg (SImode, operands[1]);
2698 emit_move_insn (operands[0], temp);
2699 return true;
2701 return false;
2704 /* Expand shift operations. */
2706 microblaze_expand_shift (rtx operands[])
2708 gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
2709 || (GET_CODE (operands[2]) == REG)
2710 || (GET_CODE (operands[2]) == SUBREG));
2712 /* Shift by one -- generate pattern. */
2713 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
2714 return 0;
2716 /* Have barrel shifter and shift > 1: use it. */
2717 if (TARGET_BARREL_SHIFT)
2718 return 0;
2720 gcc_assert ((GET_CODE (operands[0]) == REG)
2721 || (GET_CODE (operands[0]) == SUBREG)
2722 || (GET_CODE (operands[1]) == REG)
2723 || (GET_CODE (operands[1]) == SUBREG));
2725 /* Shift by zero -- copy regs if necessary. */
2726 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 0))
2728 if (REGNO (operands[0]) != REGNO (operands[1]))
2729 emit_insn (gen_movsi (operands[0], operands[1]));
2730 return 1;
2733 return 0;
2736 /* Return an RTX indicating where the return address to the
2737 calling function can be found. */
2739 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
2741 if (count != 0)
2742 return NULL_RTX;
2744 return gen_rtx_PLUS (Pmode,
2745 get_hard_reg_initial_val (Pmode,
2746 MB_ABI_SUB_RETURN_ADDR_REGNUM),
2747 GEN_INT (8));
2750 /* Put string into .sdata2 if below threashold. */
2751 void
2752 microblaze_asm_output_ident (FILE *file ATTRIBUTE_UNUSED, const char *string)
2754 int size = strlen (string) + 1;
2755 if (size <= microblaze_section_threshold)
2756 switch_to_section (sdata2_section);
2757 else
2758 switch_to_section (readonly_data_section);
2759 assemble_string (string, size);
2762 static void
2763 microblaze_elf_asm_init_sections (void)
2765 sdata2_section
2766 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
2767 SDATA2_SECTION_ASM_OP);
2770 /* Generate assembler code for constant parts of a trampoline. */
2772 static void
2773 microblaze_asm_trampoline_template (FILE *f)
2775 fprintf (f, "\t.word\t0x03e00821\t\t# move $1,$31\n");
2776 fprintf (f, "\t.word\t0x04110001\t\t# bgezal $0,.+8\n");
2777 fprintf (f, "\t.word\t0x00000000\t\t# nop\n");
2778 fprintf (f, "\t.word\t0x8fe30014\t\t# lw $3,20($31)\n");
2779 fprintf (f, "\t.word\t0x8fe20018\t\t# lw $2,24($31)\n");
2780 fprintf (f, "\t.word\t0x0060c821\t\t# move $25,$3 (abicalls)\n");
2781 fprintf (f, "\t.word\t0x00600008\t\t# jr $3\n");
2782 fprintf (f, "\t.word\t0x0020f821\t\t# move $31,$1\n");
2783 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
2784 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
2787 /* Implement TARGET_TRAMPOLINE_INIT. */
2789 static void
2790 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
2792 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2793 rtx mem;
2795 emit_block_move (m_tramp, assemble_trampoline_template (),
2796 GEN_INT (8*UNITS_PER_WORD), BLOCK_OP_NORMAL);
2798 mem = adjust_address (m_tramp, SImode, 8);
2799 emit_move_insn (mem, chain_value);
2800 mem = adjust_address (m_tramp, SImode, 12);
2801 emit_move_insn (mem, fnaddr);
2804 /* Emit instruction to perform compare.
2805 cmp is (compare_op op0 op1). */
2806 static rtx
2807 microblaze_emit_compare (enum machine_mode mode, rtx cmp, enum rtx_code *cmp_code)
2809 rtx cmp_op0 = XEXP (cmp, 0);
2810 rtx cmp_op1 = XEXP (cmp, 1);
2811 rtx comp_reg = gen_reg_rtx (SImode);
2812 enum rtx_code code = *cmp_code;
2814 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
2816 /* If comparing against zero, just test source reg. */
2817 if (cmp_op1 == const0_rtx)
2818 return cmp_op0;
2820 if (code == EQ || code == NE)
2822 if (TARGET_PATTERN_COMPARE && GET_CODE(cmp_op1) == REG)
2824 if (code == EQ)
2825 emit_insn (gen_seq_internal_pat (comp_reg, cmp_op0, cmp_op1));
2826 else
2828 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0, cmp_op1));
2829 *cmp_code = EQ;
2832 else
2833 /* Use xor for equal/not-equal comparison. */
2834 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
2836 else if (code == GT || code == GTU || code == LE || code == LEU)
2838 /* MicroBlaze compare is not symmetrical. */
2839 /* Swap argument order. */
2840 cmp_op1 = force_reg (mode, cmp_op1);
2841 if (code == GT || code == LE)
2842 emit_insn (gen_signed_compare (comp_reg, cmp_op0, cmp_op1));
2843 else
2844 emit_insn (gen_unsigned_compare (comp_reg, cmp_op0, cmp_op1));
2845 /* Translate test condition. */
2846 *cmp_code = swap_condition (code);
2848 else /* if (code == GE || code == GEU || code == LT || code == LTU) */
2850 cmp_op1 = force_reg (mode, cmp_op1);
2851 if (code == GE || code == LT)
2852 emit_insn (gen_signed_compare (comp_reg, cmp_op1, cmp_op0));
2853 else
2854 emit_insn (gen_unsigned_compare (comp_reg, cmp_op1, cmp_op0));
2857 return comp_reg;
2860 /* Generate conditional branch -- first, generate test condition,
2861 second, generate correct branch instruction. */
2863 void
2864 microblaze_expand_conditional_branch (enum machine_mode mode, rtx operands[])
2866 enum rtx_code code = GET_CODE (operands[0]);
2867 rtx comp;
2868 rtx condition;
2870 comp = microblaze_emit_compare (mode, operands[0], &code);
2871 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp, const0_rtx);
2872 emit_jump_insn (gen_condjump (condition, operands[3]));
2875 void
2876 microblaze_expand_conditional_branch_sf (rtx operands[])
2878 rtx condition;
2879 rtx cmp_op0 = XEXP (operands[0], 0);
2880 rtx cmp_op1 = XEXP (operands[0], 1);
2881 rtx comp_reg = gen_reg_rtx (SImode);
2883 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
2884 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
2885 emit_jump_insn (gen_condjump (condition, operands[3]));
2888 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
2890 static bool
2891 microblaze_frame_pointer_required (void)
2893 /* If the function contains dynamic stack allocations, we need to
2894 use the frame pointer to access the static parts of the frame. */
2895 if (cfun->calls_alloca)
2896 return true;
2897 return false;
2900 void
2901 microblaze_expand_divide (rtx operands[])
2903 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
2905 rtx regt1 = gen_reg_rtx (SImode);
2906 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
2907 rtx regqi = gen_reg_rtx (QImode);
2908 rtx div_label = gen_label_rtx ();
2909 rtx div_end_label = gen_label_rtx ();
2910 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
2911 rtx mem_rtx;
2912 rtx ret;
2913 rtx jump, cjump, insn;
2915 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
2916 cjump = emit_jump_insn_after (gen_cbranchsi4 (
2917 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
2918 regt1, GEN_INT (15), div_label), insn);
2919 LABEL_NUSES (div_label) = 1;
2920 JUMP_LABEL (cjump) = div_label;
2921 emit_insn (gen_rtx_CLOBBER (SImode, reg18));
2923 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
2924 emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
2925 mem_rtx = gen_rtx_MEM (QImode,
2926 gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
2928 insn = emit_insn (gen_movqi (regqi, mem_rtx));
2929 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
2930 jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
2931 JUMP_LABEL (jump) = div_end_label;
2932 LABEL_NUSES (div_end_label) = 1;
2933 emit_barrier ();
2935 emit_label (div_label);
2936 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
2937 operands[0], LCT_NORMAL,
2938 GET_MODE (operands[0]), 2, operands[1],
2939 GET_MODE (operands[1]), operands[2],
2940 GET_MODE (operands[2]));
2941 if (ret != operands[0])
2942 emit_move_insn (operands[0], ret);
2944 emit_label (div_end_label);
2945 emit_insn (gen_blockage ());
2948 /* Implement TARGET_FUNCTION_VALUE. */
2949 static rtx
2950 microblaze_function_value (const_tree valtype,
2951 const_tree func ATTRIBUTE_UNUSED,
2952 bool outgoing ATTRIBUTE_UNUSED)
2954 return LIBCALL_VALUE (TYPE_MODE (valtype));
2957 /* Implement TARGET_SCHED_ADJUST_COST. */
2958 static int
2959 microblaze_adjust_cost (rtx insn ATTRIBUTE_UNUSED, rtx link,
2960 rtx dep ATTRIBUTE_UNUSED, int cost)
2962 if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
2963 return cost;
2964 if (REG_NOTE_KIND (link) != 0)
2965 return 0;
2966 return cost;
2969 #undef TARGET_ENCODE_SECTION_INFO
2970 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
2972 #undef TARGET_ASM_GLOBALIZE_LABEL
2973 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
2975 #undef TARGET_ASM_FUNCTION_PROLOGUE
2976 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
2978 #undef TARGET_ASM_FUNCTION_EPILOGUE
2979 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
2981 #undef TARGET_RTX_COSTS
2982 #define TARGET_RTX_COSTS microblaze_rtx_costs
2984 #undef TARGET_ADDRESS_COST
2985 #define TARGET_ADDRESS_COST microblaze_address_cost
2987 #undef TARGET_ATTRIBUTE_TABLE
2988 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
2990 #undef TARGET_IN_SMALL_DATA_P
2991 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
2993 #undef TARGET_ASM_SELECT_SECTION
2994 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
2996 #undef TARGET_HAVE_SRODATA_SECTION
2997 #define TARGET_HAVE_SRODATA_SECTION true
2999 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3000 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3001 microblaze_function_end_prologue
3003 #undef TARGET_HANDLE_OPTION
3004 #define TARGET_HANDLE_OPTION microblaze_handle_option
3006 #undef TARGET_DEFAULT_TARGET_FLAGS
3007 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
3009 #undef TARGET_ARG_PARTIAL_BYTES
3010 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3012 #undef TARGET_FUNCTION_ARG
3013 #define TARGET_FUNCTION_ARG microblaze_function_arg
3015 #undef TARGET_FUNCTION_ARG_ADVANCE
3016 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3018 #undef TARGET_CAN_ELIMINATE
3019 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3021 #undef TARGET_LEGITIMIZE_ADDRESS
3022 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3024 #undef TARGET_LEGITIMATE_ADDRESS_P
3025 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3027 #undef TARGET_FRAME_POINTER_REQUIRED
3028 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3030 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3031 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3033 #undef TARGET_TRAMPOLINE_INIT
3034 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3036 #undef TARGET_PROMOTE_FUNCTION_MODE
3037 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3039 #undef TARGET_FUNCTION_VALUE
3040 #define TARGET_FUNCTION_VALUE microblaze_function_value
3042 #undef TARGET_SECONDARY_RELOAD
3043 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3045 #undef TARGET_SCHED_ADJUST_COST
3046 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3048 #undef TARGET_ASM_INIT_SECTIONS
3049 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3051 #undef TARGET_OPTION_OVERRIDE
3052 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3054 #undef TARGET_OPTION_OPTIMIZATION_TABLE
3055 #define TARGET_OPTION_OPTIMIZATION_TABLE microblaze_option_optimization_table
3057 #undef TARGET_EXCEPT_UNWIND_INFO
3058 #define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info
3060 struct gcc_target targetm = TARGET_INITIALIZER;
3062 #include "gt-microblaze.h"