]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/microblaze/microblaze.c
Wrap option names in gcc internal messages with %< and %>.
[thirdparty/gcc.git] / gcc / config / microblaze / microblaze.c
1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2019 Free Software Foundation, Inc.
3
4 Contributed by Michael Eager <eager@eagercon.com>.
5
6 This file is part of GCC.
7
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.
12
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.
17
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/>. */
21
22 #define IN_TARGET_CODE 1
23
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "backend.h"
28 #include "target.h"
29 #include "rtl.h"
30 #include "tree.h"
31 #include "stringpool.h"
32 #include "attribs.h"
33 #include "df.h"
34 #include "memmodel.h"
35 #include "tm_p.h"
36 #include "optabs.h"
37 #include "regs.h"
38 #include "emit-rtl.h"
39 #include "recog.h"
40 #include "cgraph.h"
41 #include "diagnostic-core.h"
42 #include "varasm.h"
43 #include "stor-layout.h"
44 #include "calls.h"
45 #include "explow.h"
46 #include "expr.h"
47 #include "reload.h"
48 #include "output.h"
49 #include "builtins.h"
50 #include "rtl-iter.h"
51 #include "cfgloop.h"
52 #include "insn-addr.h"
53 #include "cfgrtl.h"
54
55 /* This file should be included last. */
56 #include "target-def.h"
57
58 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
59
60 /* Classifies an address.
61
62 ADDRESS_INVALID
63 An invalid address.
64
65 ADDRESS_REG
66
67 A natural register or a register + const_int offset address.
68 The register satisfies microblaze_valid_base_register_p and the
69 offset is a const_arith_operand.
70
71 ADDRESS_REG_INDEX
72
73 A natural register offset by the index contained in an index register. The base
74 register satisfies microblaze_valid_base_register_p and the index register
75 satisfies microblaze_valid_index_register_p
76
77 ADDRESS_CONST_INT
78
79 A signed 16/32-bit constant address.
80
81 ADDRESS_SYMBOLIC:
82
83 A constant symbolic address or a (register + symbol). */
84
85 enum microblaze_address_type
86 {
87 ADDRESS_INVALID,
88 ADDRESS_REG,
89 ADDRESS_REG_INDEX,
90 ADDRESS_CONST_INT,
91 ADDRESS_SYMBOLIC,
92 ADDRESS_GOTOFF,
93 ADDRESS_PLT,
94 ADDRESS_TLS,
95 ADDRESS_SYMBOLIC_TXT_REL
96 };
97
98 /* Classifies symbols
99
100 SYMBOL_TYPE_GENERAL
101
102 A general symbol. */
103 enum microblaze_symbol_type
104 {
105 SYMBOL_TYPE_INVALID,
106 SYMBOL_TYPE_GENERAL
107 };
108
109 /* TLS Address Type. */
110 enum tls_reloc {
111 TLS_GD,
112 TLS_LDM,
113 TLS_DTPREL,
114 TLS_IE,
115 TLS_LE
116 };
117
118 /* Classification of a MicroBlaze address. */
119 struct microblaze_address_info
120 {
121 enum microblaze_address_type type;
122 rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
123 ADDRESS_SYMBOLIC. */
124 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
125 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
126 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
127 enum microblaze_symbol_type symbol_type;
128 enum tls_reloc tls_type;
129 };
130
131 /* Structure to be filled in by compute_frame_size with register
132 save masks, and offsets for the current function. */
133
134 struct GTY(()) microblaze_frame_info {
135 long total_size; /* # bytes that the entire frame takes up. */
136 long var_size; /* # bytes that variables take up. */
137 long args_size; /* # bytes that outgoing arguments take up. */
138 int link_debug_size; /* # bytes for the link reg and back pointer. */
139 int gp_reg_size; /* # bytes needed to store gp regs. */
140 long gp_offset; /* offset from new sp to store gp registers. */
141 long mask; /* mask of saved gp registers. */
142 int initialized; /* != 0 if frame size already calculated. */
143 int num_gp; /* number of gp registers saved. */
144 long insns_len; /* length of insns. */
145 int alloc_stack; /* Flag to indicate if the current function
146 must not create stack space. (As an optimization). */
147 };
148
149 /* Global variables for machine-dependent things. */
150
151 /* Toggle which pipleline interface to use. */
152 static GTY(()) int microblaze_sched_use_dfa = 0;
153
154 /* Threshold for data being put into the small data/bss area, instead
155 of the normal data area (references to the small data/bss area take
156 1 instruction, and use the global pointer, references to the normal
157 data area takes 2 instructions). */
158 int microblaze_section_threshold = -1;
159
160 /* Prevent scheduling potentially exception causing instructions in
161 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
162 int microblaze_no_unsafe_delay;
163
164 /* Set to one if the targeted core has the CLZ insn. */
165 int microblaze_has_clz = 0;
166
167 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
168 version having only a particular type of pipeline. There can still be
169 options on the CPU to scale pipeline features up or down. :(
170 Bad Presentation (??), so we let the MD file rely on the value of
171 this variable instead Making PIPE_5 the default. It should be backward
172 optimal with PIPE_3 MicroBlazes. */
173 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
174
175 /* High and low marks for floating point values which we will accept
176 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
177 initialized in override_options. */
178 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
179
180 /* Array giving truth value on whether or not a given hard register
181 can support a given mode. */
182 static char microblaze_hard_regno_mode_ok_p[(int)MAX_MACHINE_MODE]
183 [FIRST_PSEUDO_REGISTER];
184
185 /* Current frame information calculated by compute_frame_size. */
186 struct microblaze_frame_info current_frame_info;
187
188 /* Zero structure to initialize current_frame_info. */
189 struct microblaze_frame_info zero_frame_info;
190
191 /* List of all MICROBLAZE punctuation characters used by print_operand. */
192 char microblaze_print_operand_punct[256];
193
194 /* Map GCC register number to debugger register number. */
195 int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
196
197 /* Map hard register number to register class. */
198 enum reg_class microblaze_regno_to_class[] =
199 {
200 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
201 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
202 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
203 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
204 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
205 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
206 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
207 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
208 ST_REGS, GR_REGS, GR_REGS, GR_REGS
209 };
210
211 /* MicroBlaze specific machine attributes.
212 interrupt_handler - Interrupt handler attribute to add interrupt prologue
213 and epilogue and use appropriate interrupt return.
214 save_volatiles - Similar to interrupt handler, but use normal return. */
215 int interrupt_handler;
216 int break_handler;
217 int fast_interrupt;
218 int save_volatiles;
219
220 const struct attribute_spec microblaze_attribute_table[] = {
221 /* name min_len, max_len, decl_req, type_req, fn_type_req,
222 affects_type_identity, handler, exclude */
223 {"interrupt_handler", 0, 0, true, false, false, false, NULL, NULL },
224 {"break_handler", 0, 0, true, false, false, false, NULL, NULL },
225 {"fast_interrupt", 0, 0, true, false, false, false, NULL, NULL },
226 {"save_volatiles", 0, 0, true, false, false, false, NULL, NULL },
227 { NULL, 0, 0, false, false, false, false, NULL, NULL }
228 };
229
230 static int microblaze_interrupt_function_p (tree);
231
232 static void microblaze_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
233 static void microblaze_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
234
235 section *sdata2_section;
236
237 #ifdef HAVE_AS_TLS
238 #undef TARGET_HAVE_TLS
239 #define TARGET_HAVE_TLS true
240 #endif
241
242 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
243 static bool
244 microblaze_const_double_ok (rtx op, machine_mode mode)
245 {
246 REAL_VALUE_TYPE d;
247
248 if (GET_CODE (op) != CONST_DOUBLE)
249 return 0;
250
251 if (GET_MODE (op) == VOIDmode)
252 return 1;
253
254 if (mode != SFmode && mode != DFmode)
255 return 0;
256
257 if (op == CONST0_RTX (mode))
258 return 1;
259
260 d = *CONST_DOUBLE_REAL_VALUE (op);
261
262 if (REAL_VALUE_ISNAN (d))
263 return FALSE;
264
265 if (REAL_VALUE_NEGATIVE (d))
266 d = real_value_negate (&d);
267
268 if (mode == DFmode)
269 {
270 if (real_less (&d, &dfhigh) && real_less (&dflow, &d))
271 return 1;
272 }
273 else
274 {
275 if (real_less (&d, &sfhigh) && real_less (&sflow, &d))
276 return 1;
277 }
278
279 return 0;
280 }
281
282 /* Return truth value if a memory operand fits in a single instruction
283 (ie, register + small offset) or (register + register). */
284
285 int
286 simple_memory_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
287 {
288 rtx addr, plus0, plus1;
289
290 /* Eliminate non-memory operations. */
291 if (GET_CODE (op) != MEM)
292 return 0;
293
294 /* dword operations really put out 2 instructions, so eliminate them. */
295 /* ??? This isn't strictly correct. It is OK to accept multiword modes
296 here, since the length attributes are being set correctly, but only
297 if the address is offsettable. */
298 if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
299 return 0;
300
301
302 /* Decode the address now. */
303 addr = XEXP (op, 0);
304 switch (GET_CODE (addr))
305
306 {
307 case REG:
308 return 1;
309
310 case PLUS:
311 plus0 = XEXP (addr, 0);
312 plus1 = XEXP (addr, 1);
313
314 if (GET_CODE (plus0) != REG)
315 return 0;
316
317 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
318 && SMALL_INT (plus1))
319 {
320 return 1;
321 }
322 else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
323 {
324 return 1;
325 }
326 else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
327 {
328 return 1;
329 }
330 else
331 return 0;
332
333 case SYMBOL_REF:
334 return 0;
335
336 default:
337 break;
338 }
339
340 return 0;
341 }
342
343 /* Return nonzero for a memory address that can be used to load or store
344 a doubleword. */
345
346 int
347 double_memory_operand (rtx op, machine_mode mode)
348 {
349 rtx addr;
350
351 if (GET_CODE (op) != MEM || !memory_operand (op, mode))
352 {
353 /* During reload, we accept a pseudo register if it has an
354 appropriate memory address. If we don't do this, we will
355 wind up reloading into a register, and then reloading that
356 register from memory, when we could just reload directly from
357 memory. */
358 if (reload_in_progress
359 && GET_CODE (op) == REG
360 && REGNO (op) >= FIRST_PSEUDO_REGISTER
361 && reg_renumber[REGNO (op)] < 0
362 && reg_equiv_mem (REGNO (op)) != 0
363 && double_memory_operand (reg_equiv_mem (REGNO (op)), mode))
364 return 1;
365 return 0;
366 }
367
368 /* Make sure that 4 added to the address is a valid memory address.
369 This essentially just checks for overflow in an added constant. */
370
371 addr = XEXP (op, 0);
372
373 if (CONSTANT_ADDRESS_P (addr))
374 return 1;
375
376 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
377 ? E_SImode : E_SFmode),
378 plus_constant (Pmode, addr, 4));
379 }
380
381 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
382 int
383 microblaze_regno_ok_for_base_p (int regno, int strict)
384 {
385 if (regno >= FIRST_PSEUDO_REGISTER)
386 {
387 if (!strict)
388 return true;
389 regno = reg_renumber[regno];
390 }
391
392 /* These fake registers will be eliminated to either the stack or
393 hard frame pointer, both of which are usually valid base registers.
394 Reload deals with the cases where the eliminated form isn't valid. */
395 if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
396 return true;
397
398 return GP_REG_P (regno);
399 }
400
401 /* Return true if X is a valid base register for the given mode.
402 Allow only hard registers if STRICT. */
403
404 static bool
405 microblaze_valid_base_register_p (rtx x,
406 machine_mode mode ATTRIBUTE_UNUSED,
407 int strict)
408 {
409 if (!strict && GET_CODE (x) == SUBREG)
410 x = SUBREG_REG (x);
411
412 return (GET_CODE (x) == REG
413 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
414 }
415
416 /* Build the SYMBOL_REF for __tls_get_addr. */
417
418 static GTY(()) rtx tls_get_addr_libfunc;
419
420 static rtx
421 get_tls_get_addr (void)
422 {
423 if (!tls_get_addr_libfunc)
424 tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
425 return tls_get_addr_libfunc;
426 }
427
428 /* Return TRUE if X is a thread-local symbol. */
429 bool
430 microblaze_tls_symbol_p (rtx x)
431 {
432 if (!TARGET_HAVE_TLS)
433 return false;
434
435 if (GET_CODE (x) != SYMBOL_REF)
436 return false;
437
438 return SYMBOL_REF_TLS_MODEL (x) != 0;
439 }
440
441 /* Return TRUE if X contains any TLS symbol references. */
442
443 bool
444 microblaze_tls_referenced_p (rtx x)
445 {
446 if (!TARGET_HAVE_TLS)
447 return false;
448 subrtx_iterator::array_type array;
449 FOR_EACH_SUBRTX (iter, array, x, ALL)
450 {
451 const_rtx x = *iter;
452 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0)
453 return true;
454 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
455 TLS offsets, not real symbol references. */
456 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
457 iter.skip_subrtxes ();
458 }
459 return false;
460 }
461
462 bool
463 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
464 {
465 return microblaze_tls_referenced_p(x);
466 }
467
468 /* Return TRUE if X references a SYMBOL_REF. */
469 int
470 symbol_mentioned_p (rtx x)
471 {
472 const char * fmt;
473 int i;
474
475 if (GET_CODE (x) == SYMBOL_REF)
476 return 1;
477
478 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
479 are constant offsets, not symbols. */
480 if (GET_CODE (x) == UNSPEC)
481 return 0;
482
483 fmt = GET_RTX_FORMAT (GET_CODE (x));
484
485 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
486 {
487 if (fmt[i] == 'E')
488 {
489 int j;
490
491 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
492 if (symbol_mentioned_p (XVECEXP (x, i, j)))
493 return 1;
494 }
495 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
496 return 1;
497 }
498
499 return 0;
500 }
501
502 /* Return TRUE if X references a LABEL_REF. */
503 int
504 label_mentioned_p (rtx x)
505 {
506 const char * fmt;
507 int i;
508
509 if (GET_CODE (x) == LABEL_REF)
510 return 1;
511
512 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
513 instruction, but they are constant offsets, not symbols. */
514 if (GET_CODE (x) == UNSPEC)
515 return 0;
516
517 fmt = GET_RTX_FORMAT (GET_CODE (x));
518 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
519 {
520 if (fmt[i] == 'E')
521 {
522 int j;
523
524 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
525 if (label_mentioned_p (XVECEXP (x, i, j)))
526 return 1;
527 }
528 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
529 return 1;
530 }
531
532 return 0;
533 }
534
535 int
536 tls_mentioned_p (rtx x)
537 {
538 switch (GET_CODE (x))
539 {
540 case CONST:
541 return tls_mentioned_p (XEXP (x, 0));
542
543 case UNSPEC:
544 if (XINT (x, 1) == UNSPEC_TLS)
545 return 1;
546 return 0;
547
548 default:
549 return 0;
550 }
551 }
552
553 static rtx
554 load_tls_operand (rtx x, rtx reg)
555 {
556 rtx tmp;
557
558 if (reg == NULL_RTX)
559 reg = gen_reg_rtx (Pmode);
560
561 tmp = gen_rtx_CONST (Pmode, x);
562
563 emit_insn (gen_rtx_SET (reg,
564 gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
565
566 return reg;
567 }
568
569 static rtx_insn *
570 microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
571 {
572 rtx_insn *insns;
573 rtx tls_entry;
574
575 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
576
577 start_sequence ();
578
579 tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
580 UNSPEC_TLS);
581
582 reg = load_tls_operand (tls_entry, reg);
583
584 *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
585 LCT_PURE, /* LCT_CONST? */
586 Pmode, reg, Pmode);
587
588 insns = get_insns ();
589 end_sequence ();
590
591 return insns;
592 }
593
594 rtx
595 microblaze_legitimize_tls_address(rtx x, rtx reg)
596 {
597 rtx dest, ret, eqv, addend;
598 rtx_insn *insns;
599 enum tls_model model;
600 model = SYMBOL_REF_TLS_MODEL (x);
601
602 switch (model)
603 {
604 case TLS_MODEL_LOCAL_DYNAMIC:
605 case TLS_MODEL_GLOBAL_DYNAMIC:
606 case TLS_MODEL_INITIAL_EXEC:
607 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
608 dest = gen_reg_rtx (Pmode);
609 emit_libcall_block (insns, dest, ret, x);
610 break;
611
612 case TLS_MODEL_LOCAL_EXEC:
613 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
614
615 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
616 share the LDM result with other LD model accesses. */
617 eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
618 dest = gen_reg_rtx (Pmode);
619 emit_libcall_block (insns, dest, ret, eqv);
620
621 /* Load the addend. */
622 addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
623 UNSPEC_TLS);
624 addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
625 dest = gen_rtx_PLUS (Pmode, dest, addend);
626 break;
627
628 default:
629 gcc_unreachable ();
630 }
631 return dest;
632 }
633
634 static bool
635 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
636 {
637 info->symbol_type = SYMBOL_TYPE_GENERAL;
638 info->symbol = XVECEXP (x, 0, 0);
639
640 if (XINT (x, 1) == UNSPEC_GOTOFF)
641 {
642 info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
643 info->type = ADDRESS_GOTOFF;
644 }
645 else if (XINT (x, 1) == UNSPEC_PLT)
646 {
647 info->type = ADDRESS_PLT;
648 }
649 else if (XINT (x, 1) == UNSPEC_TLS)
650 {
651 info->type = ADDRESS_TLS;
652 info->tls_type = tls_reloc (INTVAL (XVECEXP (x, 0, 1)));
653 }
654 else if (XINT (x, 1) == UNSPEC_TEXT)
655 {
656 info->type = ADDRESS_SYMBOLIC_TXT_REL;
657 }
658 else
659 {
660 return false;
661 }
662 return true;
663 }
664
665
666 /* Return true if X is a valid index register for the given mode.
667 Allow only hard registers if STRICT. */
668
669 static bool
670 microblaze_valid_index_register_p (rtx x,
671 machine_mode mode ATTRIBUTE_UNUSED,
672 int strict)
673 {
674 if (!strict && GET_CODE (x) == SUBREG)
675 x = SUBREG_REG (x);
676
677 return (GET_CODE (x) == REG
678 /* A base register is good enough to be an index register on MicroBlaze. */
679 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
680 }
681
682 /* Get the base register for accessing a value from the memory or
683 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
684 static int
685 get_base_reg (rtx x)
686 {
687 tree decl;
688 int base_reg;
689
690 if (!flag_pic || microblaze_tls_symbol_p(x))
691 base_reg = MB_ABI_BASE_REGNUM;
692 else if (flag_pic)
693 base_reg = MB_ABI_PIC_ADDR_REGNUM;
694
695 if (TARGET_XLGPOPT
696 && GET_CODE (x) == SYMBOL_REF
697 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
698 {
699 if (TREE_READONLY (decl))
700 base_reg = MB_ABI_GPRO_REGNUM;
701 else
702 base_reg = MB_ABI_GPRW_REGNUM;
703 }
704
705 return base_reg;
706 }
707
708 /* Return true if X is a valid address for machine mode MODE. If it is,
709 fill in INFO appropriately.
710 STRICT > 0 if we should only accept hard base registers.
711 STRICT = 2 if the operand address is being printed thus
712 function has been called by print_operand_address.
713
714 type regA regB offset symbol
715
716 ADDRESS_INVALID NULL NULL NULL NULL
717
718 ADDRESS_REG %0 NULL const_0 / NULL
719 const_int
720 ADDRESS_REG_INDEX %0 %1 NULL NULL
721
722 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
723 sda_base_reg
724
725 ADDRESS_CONST_INT r0 NULL const NULL
726
727 For modes spanning multiple registers (DFmode in 32-bit GPRs,
728 DImode, TImode), indexed addressing cannot be used because
729 adjacent memory cells are accessed by adding word-sized offsets
730 during assembly output. */
731
732 static bool
733 microblaze_classify_address (struct microblaze_address_info *info, rtx x,
734 machine_mode mode, int strict)
735 {
736 rtx xplus0;
737 rtx xplus1;
738 rtx offset;
739
740 info->type = ADDRESS_INVALID;
741 info->regA = NULL;
742 info->regB = NULL;
743 info->offset = NULL;
744 info->symbol = NULL;
745 info->symbol_type = SYMBOL_TYPE_INVALID;
746 offset = NULL;
747
748 switch (GET_CODE (x))
749 {
750 case REG:
751 case SUBREG:
752 {
753 info->type = ADDRESS_REG;
754 info->regA = x;
755 info->offset = const0_rtx;
756 return microblaze_valid_base_register_p (info->regA, mode, strict);
757 }
758 case PLUS:
759 {
760 xplus0 = XEXP (x, 0);
761 xplus1 = XEXP (x, 1);
762
763 if (microblaze_valid_base_register_p (xplus0, mode, strict))
764 {
765 info->type = ADDRESS_REG;
766 info->regA = xplus0;
767
768 if (GET_CODE (xplus1) == CONST_INT)
769 {
770 info->offset = xplus1;
771 return true;
772 }
773 else if (GET_CODE (xplus1) == UNSPEC)
774 {
775 /* Need offsettable address. */
776 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
777 return false;
778
779 return microblaze_classify_unspec (info, xplus1);
780 }
781 else if ((GET_CODE (xplus1) == SYMBOL_REF ||
782 GET_CODE (xplus1) == LABEL_REF))
783 {
784 if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
785 return false;
786 info->type = ADDRESS_SYMBOLIC;
787 info->symbol = xplus1;
788 info->symbol_type = SYMBOL_TYPE_GENERAL;
789 return true;
790 }
791 else if (GET_CODE (xplus1) == CONST)
792 {
793 rtx xconst0 = XEXP(xplus1, 0);
794
795 /* base + unspec. */
796 if (GET_CODE (xconst0) == UNSPEC)
797 {
798 /* Need offsettable address. */
799 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
800 return false;
801 return microblaze_classify_unspec(info, xconst0);
802 }
803
804 /* for (plus x const_int) just look at x. */
805 if (GET_CODE (xconst0) == PLUS
806 && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
807 && (SMALL_INT (XEXP (xconst0, 1))
808 || GET_CODE (XEXP (xconst0, 0)) == UNSPEC))
809 {
810 /* Hold CONST_INT Value in offset in case of
811 UNSPEC + CONST_INT. */
812 offset = XEXP (xconst0, 1);
813
814 /* This is ok as info->symbol is set to xplus1 the full
815 const-expression below. */
816 xconst0 = XEXP (xconst0, 0);
817 }
818
819 if (GET_CODE (xconst0) == SYMBOL_REF
820 || GET_CODE (xconst0) == LABEL_REF)
821 {
822 if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
823 return false;
824
825 info->type = ADDRESS_SYMBOLIC;
826 info->symbol = xplus1;
827 info->symbol_type = SYMBOL_TYPE_GENERAL;
828 return true;
829 }
830
831 if (GET_CODE (xconst0) == UNSPEC && TARGET_PIC_DATA_TEXT_REL)
832 {
833 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
834 return false;
835
836 info->offset = offset;
837 return microblaze_classify_unspec (info, xconst0);
838 }
839
840 /* Not base + symbol || base + UNSPEC. */
841 return false;
842
843 }
844 else if (GET_CODE (xplus1) == REG
845 && microblaze_valid_index_register_p (xplus1, mode,
846 strict)
847 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
848 {
849 /* Restrict larger than word-width modes from using an index register. */
850 info->type = ADDRESS_REG_INDEX;
851 info->regB = xplus1;
852 return true;
853 }
854 }
855 break;
856 }
857 case CONST_INT:
858 {
859 info->regA = gen_raw_REG (mode, 0);
860 info->type = ADDRESS_CONST_INT;
861 info->offset = x;
862 return true;
863 }
864 case CONST:
865 case LABEL_REF:
866 case SYMBOL_REF:
867 {
868 info->type = ADDRESS_SYMBOLIC;
869 info->symbol_type = SYMBOL_TYPE_GENERAL;
870 info->symbol = x;
871 info->regA = gen_raw_REG (mode, get_base_reg (x));
872
873 if (GET_CODE (x) == CONST)
874 {
875 if (GET_CODE (XEXP (x, 0)) == UNSPEC)
876 {
877 info->regA = gen_raw_REG (mode,
878 get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
879 return microblaze_classify_unspec (info, XEXP (x, 0));
880 }
881 return !(flag_pic && pic_address_needs_scratch (x));
882 }
883
884 /* Avoid error in print_operand_address in case UNSPEC
885 is removed from SYMBOL or LABEL REFS during optimization. */
886 if ((GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
887 && flag_pic && TARGET_PIC_DATA_TEXT_REL && strict == 2)
888 {
889 info->type = ADDRESS_SYMBOLIC_TXT_REL;
890 return true;
891 }
892
893 if (flag_pic == 2)
894 return false;
895 else if (microblaze_tls_symbol_p(x))
896 return false;
897
898 return true;
899 }
900
901 case UNSPEC:
902 {
903 if (reload_in_progress)
904 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
905 return microblaze_classify_unspec (info, x);
906 }
907
908 default:
909 return false;
910 }
911
912 return false;
913 }
914
915 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
916 returns a nonzero value if X is a legitimate address for a memory
917 operand of the indicated MODE. STRICT is nonzero if this function
918 is called during reload. */
919
920 bool
921 microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict)
922 {
923 struct microblaze_address_info addr;
924
925 return microblaze_classify_address (&addr, x, mode, strict);
926 }
927
928 bool
929 microblaze_constant_address_p (rtx x)
930 {
931 return ((GET_CODE (x) == LABEL_REF) || (GET_CODE (x) == SYMBOL_REF)
932 || GET_CODE (x) == CONST_INT
933 || (GET_CODE (x) == CONST
934 && ! (flag_pic && pic_address_needs_scratch (x))));
935 }
936
937 int
938 microblaze_valid_pic_const (rtx x)
939 {
940 switch (GET_CODE (x))
941 {
942 case CONST:
943 case CONST_INT:
944 case CONST_DOUBLE:
945 return true;
946 default:
947 return false;
948 }
949 }
950
951 int
952 microblaze_legitimate_pic_operand (rtx x)
953 {
954 if (flag_pic == 2 && (symbol_mentioned_p (x) || label_mentioned_p (x))
955 && !(TARGET_PIC_DATA_TEXT_REL && call_insn_operand (x,VOIDmode)))
956 return 0;
957
958 if (microblaze_tls_referenced_p(x))
959 return 0;
960
961 return 1;
962 }
963
964 /* Try machine-dependent ways of modifying an illegitimate address
965 to be legitimate. If we find one, return the new, valid address.
966 This is used from only one place: `memory_address' in explow.c.
967
968 OLDX is the address as it was before break_out_memory_refs was
969 called. In some cases it is useful to look at this to decide what
970 needs to be done.
971
972 It is always safe for this function to do nothing. It exists to
973 recognize opportunities to optimize the output.
974
975 For the MicroBlaze, transform:
976
977 memory(X + <large int>)
978
979 into:
980
981 Y = <large int> & ~0x7fff;
982 Z = X + Y
983 memory (Z + (<large int> & 0x7fff));
984
985 This is for CSE to find several similar references, and only use one Z.
986
987 When PIC, convert addresses of the form memory (symbol+large int) to
988 memory (reg+large int). */
989
990 static rtx
991 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
992 machine_mode mode ATTRIBUTE_UNUSED)
993 {
994 register rtx xinsn = x, result;
995
996 if (GET_CODE (xinsn) == CONST
997 && flag_pic && pic_address_needs_scratch (xinsn))
998 {
999 rtx ptr_reg = gen_reg_rtx (Pmode);
1000 rtx constant = XEXP (XEXP (xinsn, 0), 1);
1001
1002 emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
1003
1004 result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
1005 if (SMALL_INT (constant))
1006 return result;
1007 /* Otherwise we fall through so the code below will fix the
1008 constant. */
1009 xinsn = result;
1010 }
1011
1012 if (GET_CODE (xinsn) == PLUS)
1013 {
1014 register rtx xplus0 = XEXP (xinsn, 0);
1015 register rtx xplus1 = XEXP (xinsn, 1);
1016 register enum rtx_code code0 = GET_CODE (xplus0);
1017 register enum rtx_code code1 = GET_CODE (xplus1);
1018
1019 if (code0 != REG && code1 == REG)
1020 {
1021 xplus0 = XEXP (xinsn, 1);
1022 xplus1 = XEXP (xinsn, 0);
1023 code0 = GET_CODE (xplus0);
1024 code1 = GET_CODE (xplus1);
1025 }
1026
1027 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
1028 && code1 == CONST_INT && !SMALL_INT (xplus1))
1029 {
1030 rtx int_reg = gen_reg_rtx (Pmode);
1031 rtx ptr_reg = gen_reg_rtx (Pmode);
1032
1033 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
1034
1035 emit_insn (gen_rtx_SET (ptr_reg,
1036 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
1037
1038 result = gen_rtx_PLUS (Pmode, ptr_reg,
1039 GEN_INT (INTVAL (xplus1) & 0x7fff));
1040 return result;
1041 }
1042
1043 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
1044 {
1045 if (reload_in_progress)
1046 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1047 if (code1 == CONST)
1048 {
1049 xplus1 = XEXP (xplus1, 0);
1050 code1 = GET_CODE (xplus1);
1051 }
1052 if (code1 == SYMBOL_REF)
1053 {
1054 if (microblaze_tls_symbol_p(xplus1))
1055 {
1056 rtx tls_ref, reg;
1057 reg = gen_reg_rtx (Pmode);
1058
1059 tls_ref = microblaze_legitimize_tls_address (xplus1,
1060 NULL_RTX);
1061 emit_move_insn (reg, tls_ref);
1062
1063 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1064
1065 return result;
1066 }
1067 else if (flag_pic == 2)
1068 {
1069 if (!TARGET_PIC_DATA_TEXT_REL)
1070 {
1071 rtx pic_ref, reg;
1072 reg = gen_reg_rtx (Pmode);
1073
1074 pic_ref = gen_rtx_UNSPEC (Pmode,
1075 gen_rtvec (1, xplus1),
1076 UNSPEC_GOTOFF);
1077 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1078 pic_ref = gen_rtx_PLUS (Pmode,
1079 pic_offset_table_rtx, pic_ref);
1080 pic_ref = gen_const_mem (Pmode, pic_ref);
1081 emit_move_insn (reg, pic_ref);
1082 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1083 return result;
1084 }
1085 else
1086 {
1087 rtx pic_ref, reg;
1088 reg = gen_reg_rtx (Pmode);
1089 pic_ref = gen_rtx_UNSPEC (Pmode,
1090 gen_rtvec (1, xplus1),
1091 UNSPEC_TEXT);
1092 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1093 emit_insn (gen_addsi3 (reg,
1094 pic_offset_table_rtx, xplus0));
1095 result = gen_rtx_PLUS (Pmode, reg, pic_ref);
1096 return result;
1097 }
1098 }
1099 }
1100 }
1101 }
1102
1103 if (GET_CODE (xinsn) == SYMBOL_REF)
1104 {
1105 rtx reg;
1106 if (microblaze_tls_symbol_p(xinsn))
1107 {
1108 reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
1109 }
1110 else if (flag_pic == 2)
1111 {
1112 if (reload_in_progress)
1113 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1114
1115 if (!TARGET_PIC_DATA_TEXT_REL)
1116 {
1117 rtx pic_ref;
1118
1119 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
1120 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1121 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1122 pic_ref = gen_const_mem (Pmode, pic_ref);
1123 reg = pic_ref;
1124 }
1125 else
1126 {
1127 rtx pic_ref;
1128
1129 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_TEXT);
1130 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1131 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1132 reg = pic_ref;
1133 }
1134 }
1135 return reg;
1136 }
1137
1138 return x;
1139 }
1140
1141 /* Block Moves. */
1142
1143 #define MAX_MOVE_REGS 8
1144 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1145
1146 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1147 Assume that the areas do not overlap. */
1148
1149 static void
1150 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
1151 {
1152 HOST_WIDE_INT offset, delta;
1153 unsigned HOST_WIDE_INT bits;
1154 int i;
1155 machine_mode mode;
1156 rtx *regs;
1157
1158 bits = BITS_PER_WORD;
1159 mode = int_mode_for_size (bits, 0).require ();
1160 delta = bits / BITS_PER_UNIT;
1161
1162 /* Allocate a buffer for the temporary registers. */
1163 regs = XALLOCAVEC (rtx, length / delta);
1164
1165 /* Load as many BITS-sized chunks as possible. Use a normal load if
1166 the source has enough alignment, otherwise use left/right pairs. */
1167 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1168 {
1169 regs[i] = gen_reg_rtx (mode);
1170 emit_move_insn (regs[i], adjust_address (src, mode, offset));
1171 }
1172
1173 /* Copy the chunks to the destination. */
1174 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1175 emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
1176
1177 /* Mop up any left-over bytes. */
1178 if (offset < length)
1179 {
1180 src = adjust_address (src, BLKmode, offset);
1181 dest = adjust_address (dest, BLKmode, offset);
1182 move_by_pieces (dest, src, length - offset,
1183 MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), RETURN_BEGIN);
1184 }
1185 }
1186
1187 /* Helper function for doing a loop-based block operation on memory
1188 reference MEM. Each iteration of the loop will operate on LENGTH
1189 bytes of MEM.
1190
1191 Create a new base register for use within the loop and point it to
1192 the start of MEM. Create a new memory reference that uses this
1193 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1194
1195 static void
1196 microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
1197 rtx * loop_reg, rtx * loop_mem)
1198 {
1199 *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
1200
1201 /* Although the new mem does not refer to a known location,
1202 it does keep up to LENGTH bytes of alignment. */
1203 *loop_mem = change_address (mem, BLKmode, *loop_reg);
1204 set_mem_align (*loop_mem,
1205 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
1206 length * BITS_PER_UNIT));
1207 }
1208
1209
1210 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1211 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1212 memory regions do not overlap. */
1213
1214 static void
1215 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
1216 {
1217 rtx_code_label *label;
1218 rtx src_reg, dest_reg, final_src;
1219 HOST_WIDE_INT leftover;
1220
1221 leftover = length % MAX_MOVE_BYTES;
1222 length -= leftover;
1223
1224 /* Create registers and memory references for use within the loop. */
1225 microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
1226 microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
1227
1228 /* Calculate the value that SRC_REG should have after the last iteration
1229 of the loop. */
1230 final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
1231 0, 0, OPTAB_WIDEN);
1232
1233 /* Emit the start of the loop. */
1234 label = gen_label_rtx ();
1235 emit_label (label);
1236
1237 /* Emit the loop body. */
1238 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
1239
1240 /* Move on to the next block. */
1241 emit_move_insn (src_reg, plus_constant (Pmode, src_reg, MAX_MOVE_BYTES));
1242 emit_move_insn (dest_reg, plus_constant (Pmode, dest_reg, MAX_MOVE_BYTES));
1243
1244 /* Emit the test & branch. */
1245 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
1246 src_reg, final_src, label));
1247
1248 /* Mop up any left-over bytes. */
1249 if (leftover)
1250 microblaze_block_move_straight (dest, src, leftover);
1251 }
1252
1253 /* Expand a movmemsi instruction. */
1254
1255 bool
1256 microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
1257 {
1258
1259 if (GET_CODE (length) == CONST_INT)
1260 {
1261 HOST_WIDE_INT bytes = INTVAL (length);
1262 int align = INTVAL (align_rtx);
1263
1264 if (align > UNITS_PER_WORD)
1265 {
1266 align = UNITS_PER_WORD; /* We can't do any better. */
1267 }
1268 else if (align < UNITS_PER_WORD)
1269 {
1270 if (INTVAL (length) <= MAX_MOVE_BYTES)
1271 {
1272 move_by_pieces (dest, src, bytes, align, RETURN_BEGIN);
1273 return true;
1274 }
1275 else
1276 return false;
1277 }
1278
1279 if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
1280 {
1281 microblaze_block_move_straight (dest, src, INTVAL (length));
1282 return true;
1283 }
1284 else if (optimize)
1285 {
1286 microblaze_block_move_loop (dest, src, INTVAL (length));
1287 return true;
1288 }
1289 }
1290 return false;
1291 }
1292
1293 static bool
1294 microblaze_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
1295 int opno ATTRIBUTE_UNUSED, int *total,
1296 bool speed ATTRIBUTE_UNUSED)
1297 {
1298 int code = GET_CODE (x);
1299
1300 switch (code)
1301 {
1302 case MEM:
1303 {
1304 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
1305 if (simple_memory_operand (x, mode))
1306 *total = COSTS_N_INSNS (2 * num_words);
1307 else
1308 *total = COSTS_N_INSNS (2 * (2 * num_words));
1309
1310 return true;
1311 }
1312 case NOT:
1313 {
1314 if (mode == DImode)
1315 {
1316 *total = COSTS_N_INSNS (2);
1317 }
1318 else
1319 *total = COSTS_N_INSNS (1);
1320 return false;
1321 }
1322 case AND:
1323 case IOR:
1324 case XOR:
1325 {
1326 if (mode == DImode)
1327 {
1328 *total = COSTS_N_INSNS (2);
1329 }
1330 else
1331 *total = COSTS_N_INSNS (1);
1332
1333 return false;
1334 }
1335 case ASHIFT:
1336 case ASHIFTRT:
1337 case LSHIFTRT:
1338 {
1339 if (TARGET_BARREL_SHIFT)
1340 {
1341 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1342 >= 0)
1343 *total = COSTS_N_INSNS (1);
1344 else
1345 *total = COSTS_N_INSNS (2);
1346 }
1347 else if (!TARGET_SOFT_MUL)
1348 *total = COSTS_N_INSNS (1);
1349 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1350 {
1351 /* Add 1 to make shift slightly more expensive than add. */
1352 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
1353 /* Reduce shift costs for special circumstances. */
1354 if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
1355 *total -= 2;
1356 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
1357 *total -= 2;
1358 }
1359 else
1360 /* Double the worst cost of shifts when there is no barrel shifter and
1361 the shift amount is in a reg. */
1362 *total = COSTS_N_INSNS (32 * 4);
1363 return true;
1364 }
1365 case PLUS:
1366 case MINUS:
1367 {
1368 if (mode == SFmode || mode == DFmode)
1369 {
1370 if (TARGET_HARD_FLOAT)
1371 *total = COSTS_N_INSNS (6);
1372 return true;
1373 }
1374 else if (mode == DImode)
1375 {
1376 *total = COSTS_N_INSNS (4);
1377 return true;
1378 }
1379 else
1380 {
1381 *total = COSTS_N_INSNS (1);
1382 return true;
1383 }
1384
1385 return false;
1386 }
1387 case NEG:
1388 {
1389 if (mode == DImode)
1390 *total = COSTS_N_INSNS (4);
1391
1392 return false;
1393 }
1394 case MULT:
1395 {
1396 if (mode == SFmode)
1397 {
1398 if (TARGET_HARD_FLOAT)
1399 *total = COSTS_N_INSNS (6);
1400 }
1401 else if (!TARGET_SOFT_MUL)
1402 {
1403 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1404 >= 0)
1405 *total = COSTS_N_INSNS (1);
1406 else
1407 *total = COSTS_N_INSNS (3);
1408 }
1409 else
1410 *total = COSTS_N_INSNS (10);
1411 return true;
1412 }
1413 case DIV:
1414 case UDIV:
1415 {
1416 if (mode == SFmode)
1417 {
1418 if (TARGET_HARD_FLOAT)
1419 *total = COSTS_N_INSNS (23);
1420 }
1421 return false;
1422 }
1423 case SIGN_EXTEND:
1424 {
1425 *total = COSTS_N_INSNS (1);
1426 return false;
1427 }
1428 case ZERO_EXTEND:
1429 {
1430 *total = COSTS_N_INSNS (1);
1431 return false;
1432 }
1433 }
1434
1435 return false;
1436 }
1437
1438 /* Return the number of instructions needed to load or store a value
1439 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1440
1441 static int
1442 microblaze_address_insns (rtx x, machine_mode mode)
1443 {
1444 struct microblaze_address_info addr;
1445
1446 if (microblaze_classify_address (&addr, x, mode, false))
1447 {
1448 switch (addr.type)
1449 {
1450 case ADDRESS_REG:
1451 if (SMALL_INT (addr.offset))
1452 return 1;
1453 else
1454 return 2;
1455 case ADDRESS_CONST_INT:
1456 if (SMALL_INT (x))
1457 return 1;
1458 else
1459 return 2;
1460 case ADDRESS_REG_INDEX:
1461 return 1;
1462 case ADDRESS_SYMBOLIC:
1463 case ADDRESS_SYMBOLIC_TXT_REL:
1464 case ADDRESS_GOTOFF:
1465 return 2;
1466 case ADDRESS_TLS:
1467 switch (addr.tls_type)
1468 {
1469 case TLS_GD:
1470 return 2;
1471 case TLS_LDM:
1472 return 2;
1473 case TLS_DTPREL:
1474 return 1;
1475 default :
1476 abort();
1477 }
1478 default:
1479 break;
1480 }
1481 }
1482 return 0;
1483 }
1484
1485 /* Provide the costs of an addressing mode that contains ADDR.
1486 If ADDR is not a valid address, its cost is irrelevant. */
1487 static int
1488 microblaze_address_cost (rtx addr, machine_mode mode ATTRIBUTE_UNUSED,
1489 addr_space_t as ATTRIBUTE_UNUSED,
1490 bool speed ATTRIBUTE_UNUSED)
1491 {
1492 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1493 }
1494
1495 /* Return nonzero if X is an address which needs a temporary register when
1496 reloaded while generating PIC code. */
1497
1498 int
1499 pic_address_needs_scratch (rtx x)
1500 {
1501 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
1502 {
1503 rtx p0, p1;
1504
1505 p0 = XEXP (XEXP (x, 0), 0);
1506 p1 = XEXP (XEXP (x, 0), 1);
1507
1508 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
1509 && (GET_CODE (p1) == CONST_INT)
1510 && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
1511 return 1;
1512 }
1513 return 0;
1514 }
1515
1516 /* Argument support functions. */
1517 /* Initialize CUMULATIVE_ARGS for a function. */
1518
1519 void
1520 init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1521 rtx libname ATTRIBUTE_UNUSED)
1522 {
1523 static CUMULATIVE_ARGS zero_cum;
1524 tree param, next_param;
1525
1526 *cum = zero_cum;
1527
1528 /* Determine if this function has variable arguments. This is
1529 indicated by the last argument being 'void_type_mode' if there
1530 are no variable arguments. The standard MicroBlaze calling sequence
1531 passes all arguments in the general purpose registers in this case. */
1532
1533 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1534 param != 0; param = next_param)
1535 {
1536 next_param = TREE_CHAIN (param);
1537 if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1538 cum->gp_reg_found = 1;
1539 }
1540 }
1541
1542 /* Advance the argument to the next argument position. */
1543
1544 static void
1545 microblaze_function_arg_advance (cumulative_args_t cum_v,
1546 machine_mode mode,
1547 const_tree type, bool named ATTRIBUTE_UNUSED)
1548 {
1549 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1550
1551 cum->arg_number++;
1552 switch (mode)
1553 {
1554 case E_VOIDmode:
1555 break;
1556
1557 default:
1558 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1559 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1560
1561 cum->gp_reg_found = 1;
1562 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1563 / UNITS_PER_WORD);
1564 break;
1565
1566 case E_BLKmode:
1567 cum->gp_reg_found = 1;
1568 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1569 / UNITS_PER_WORD);
1570 break;
1571
1572 case E_SFmode:
1573 cum->arg_words++;
1574 if (!cum->gp_reg_found && cum->arg_number <= 2)
1575 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1576 break;
1577
1578 case E_DFmode:
1579 cum->arg_words += 2;
1580 if (!cum->gp_reg_found && cum->arg_number <= 2)
1581 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1582 break;
1583
1584 case E_DImode:
1585 cum->gp_reg_found = 1;
1586 cum->arg_words += 2;
1587 break;
1588
1589 case E_QImode:
1590 case E_HImode:
1591 case E_SImode:
1592 case E_TImode:
1593 cum->gp_reg_found = 1;
1594 cum->arg_words++;
1595 break;
1596 }
1597 }
1598
1599 /* Return an RTL expression containing the register for the given mode,
1600 or 0 if the argument is to be passed on the stack. */
1601
1602 static rtx
1603 microblaze_function_arg (cumulative_args_t cum_v, machine_mode mode,
1604 const_tree type ATTRIBUTE_UNUSED,
1605 bool named ATTRIBUTE_UNUSED)
1606 {
1607 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1608
1609 rtx ret;
1610 int regbase = -1;
1611 int *arg_words = &cum->arg_words;
1612
1613 cum->last_arg_fp = 0;
1614 switch (mode)
1615 {
1616 case E_SFmode:
1617 case E_DFmode:
1618 case E_VOIDmode:
1619 case E_QImode:
1620 case E_HImode:
1621 case E_SImode:
1622 case E_DImode:
1623 case E_TImode:
1624 regbase = GP_ARG_FIRST;
1625 break;
1626 default:
1627 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1628 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1629 /* FALLTHRU */
1630 case E_BLKmode:
1631 regbase = GP_ARG_FIRST;
1632 break;
1633 }
1634
1635 if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1636 ret = 0;
1637 else
1638 {
1639 gcc_assert (regbase != -1);
1640
1641 ret = gen_rtx_REG (mode, regbase + *arg_words);
1642 }
1643
1644 if (mode == VOIDmode)
1645 {
1646 if (cum->num_adjusts > 0)
1647 ret = gen_rtx_PARALLEL ((machine_mode) cum->fp_code,
1648 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1649 }
1650
1651 return ret;
1652 }
1653
1654 /* Return number of bytes of argument to put in registers. */
1655 static int
1656 function_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
1657 tree type, bool named ATTRIBUTE_UNUSED)
1658 {
1659 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1660
1661 if ((mode == BLKmode
1662 || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1663 || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1664 && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1665 {
1666 int words;
1667 if (mode == BLKmode)
1668 words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1669 / UNITS_PER_WORD);
1670 else
1671 words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1672
1673 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1674 return 0; /* structure fits in registers */
1675
1676 return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1677 }
1678
1679 else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1680 return UNITS_PER_WORD;
1681
1682 return 0;
1683 }
1684
1685 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1686 for easier range comparison. */
1687 static int
1688 microblaze_version_to_int (const char *version)
1689 {
1690 const char *p, *v;
1691 const char *tmpl = "vXX.YY.Z";
1692 int iver = 0;
1693
1694 p = version;
1695 v = tmpl;
1696
1697 while (*p)
1698 {
1699 if (*v == 'X')
1700 { /* Looking for major */
1701 if (*p == '.')
1702 {
1703 v++;
1704 }
1705 else
1706 {
1707 if (!(*p >= '0' && *p <= '9'))
1708 return -1;
1709 iver += (int) (*p - '0');
1710 iver *= 10;
1711 }
1712 }
1713 else if (*v == 'Y')
1714 { /* Looking for minor */
1715 if (!(*p >= '0' && *p <= '9'))
1716 return -1;
1717 iver += (int) (*p - '0');
1718 iver *= 10;
1719 }
1720 else if (*v == 'Z')
1721 { /* Looking for compat */
1722 if (!(*p >= 'a' && *p <= 'z'))
1723 return -1;
1724 iver *= 10;
1725 iver += (int) (*p - 'a');
1726 }
1727 else
1728 {
1729 if (*p != *v)
1730 return -1;
1731 }
1732
1733 v++;
1734 p++;
1735 }
1736
1737 if (*p)
1738 return -1;
1739
1740 return iver;
1741 }
1742
1743
1744 static void
1745 microblaze_option_override (void)
1746 {
1747 register int i, start;
1748 register int regno;
1749 register machine_mode mode;
1750 int ver;
1751
1752 microblaze_section_threshold = (global_options_set.x_g_switch_value
1753 ? g_switch_value
1754 : MICROBLAZE_DEFAULT_GVALUE);
1755
1756 if (flag_pic)
1757 {
1758 /* Make sure it's 2, we only support one kind of PIC. */
1759 flag_pic = 2;
1760 if (!TARGET_SUPPORTS_PIC)
1761 {
1762 error ("%<-fPIC%>/%<-fpic%> not supported for this target");
1763 /* Clear it to avoid further errors. */
1764 flag_pic = 0;
1765 }
1766 }
1767
1768 /* Check the MicroBlaze CPU version for any special action to be done. */
1769 if (microblaze_select_cpu == NULL)
1770 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1771 ver = microblaze_version_to_int (microblaze_select_cpu);
1772 if (ver == -1)
1773 {
1774 error ("%qs is an invalid argument to %<-mcpu=%>", microblaze_select_cpu);
1775 }
1776
1777 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1778 if (ver < 0)
1779 {
1780 /* No hardware exceptions in earlier versions. So no worries. */
1781 #if 0
1782 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1783 #endif
1784 microblaze_no_unsafe_delay = 0;
1785 microblaze_pipe = MICROBLAZE_PIPE_3;
1786 }
1787 else if (ver == 0
1788 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1789 == 0))
1790 {
1791 #if 0
1792 microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1793 #endif
1794 microblaze_no_unsafe_delay = 1;
1795 microblaze_pipe = MICROBLAZE_PIPE_3;
1796 }
1797 else
1798 {
1799 /* We agree to use 5 pipe-stage model even on area optimized 3
1800 pipe-stage variants. */
1801 #if 0
1802 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1803 #endif
1804 microblaze_no_unsafe_delay = 0;
1805 microblaze_pipe = MICROBLAZE_PIPE_5;
1806 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1807 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1808 "v5.00.b") == 0
1809 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1810 "v5.00.c") == 0)
1811 {
1812 /* Pattern compares are to be turned on by default only when
1813 compiling for MB v5.00.'z'. */
1814 target_flags |= MASK_PATTERN_COMPARE;
1815 }
1816 }
1817
1818 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1819 if (ver < 0)
1820 {
1821 if (TARGET_MULTIPLY_HIGH)
1822 warning (0,
1823 "%<-mxl-multiply-high%> can be used only with "
1824 "%<-mcpu=v6.00.a%> or greater");
1825 }
1826
1827 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.10.a");
1828 microblaze_has_clz = 1;
1829 if (ver < 0)
1830 {
1831 /* MicroBlaze prior to 8.10.a didn't have clz. */
1832 microblaze_has_clz = 0;
1833 }
1834
1835 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1836 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.30.a");
1837 if (ver < 0)
1838 {
1839 if (TARGET_REORDER == 1)
1840 warning (0, "%<-mxl-reorder%> can be used only with "
1841 "%<-mcpu=v8.30.a%> or greater");
1842 TARGET_REORDER = 0;
1843 }
1844 else if ((ver == 0) && !TARGET_PATTERN_COMPARE)
1845 {
1846 if (TARGET_REORDER == 1)
1847 warning (0, "%<-mxl-reorder%> requires %<-mxl-pattern-compare%> for "
1848 "%<-mcpu=v8.30.a%>");
1849 TARGET_REORDER = 0;
1850 }
1851
1852 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1853 error ("%<-mxl-multiply-high%> requires %<-mno-xl-soft-mul%>");
1854
1855 /* Always use DFA scheduler. */
1856 microblaze_sched_use_dfa = 1;
1857
1858 #if 0
1859 microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1860 #endif
1861
1862 /* Initialize the high, low values for legit floating point constants. */
1863 real_maxval (&dfhigh, 0, DFmode);
1864 real_maxval (&dflow, 1, DFmode);
1865 real_maxval (&sfhigh, 0, SFmode);
1866 real_maxval (&sflow, 1, SFmode);
1867
1868 microblaze_print_operand_punct['?'] = 1;
1869 microblaze_print_operand_punct['#'] = 1;
1870 microblaze_print_operand_punct['&'] = 1;
1871 microblaze_print_operand_punct['!'] = 1;
1872 microblaze_print_operand_punct['*'] = 1;
1873 microblaze_print_operand_punct['@'] = 1;
1874 microblaze_print_operand_punct['.'] = 1;
1875 microblaze_print_operand_punct['('] = 1;
1876 microblaze_print_operand_punct[')'] = 1;
1877 microblaze_print_operand_punct['['] = 1;
1878 microblaze_print_operand_punct[']'] = 1;
1879 microblaze_print_operand_punct['<'] = 1;
1880 microblaze_print_operand_punct['>'] = 1;
1881 microblaze_print_operand_punct['{'] = 1;
1882 microblaze_print_operand_punct['}'] = 1;
1883 microblaze_print_operand_punct['^'] = 1;
1884 microblaze_print_operand_punct['$'] = 1;
1885 microblaze_print_operand_punct['+'] = 1;
1886
1887 /* Set up array to map GCC register number to debug register number.
1888 Ignore the special purpose register numbers. */
1889
1890 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1891 microblaze_dbx_regno[i] = -1;
1892
1893 start = GP_DBX_FIRST - GP_REG_FIRST;
1894 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1895 microblaze_dbx_regno[i] = i + start;
1896
1897 /* Set up array giving whether a given register can hold a given mode. */
1898
1899 for (mode = VOIDmode;
1900 mode != MAX_MACHINE_MODE; mode = (machine_mode) ((int) mode + 1))
1901 {
1902 register int size = GET_MODE_SIZE (mode);
1903
1904 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1905 {
1906 register int ok;
1907
1908 if (mode == CCmode)
1909 {
1910 ok = (ST_REG_P (regno) || GP_REG_P (regno));
1911 }
1912 else if (GP_REG_P (regno))
1913 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1914 else
1915 ok = 0;
1916
1917 microblaze_hard_regno_mode_ok_p[(int) mode][regno] = ok;
1918 }
1919 }
1920 }
1921
1922 /* Implement TARGET_HARD_REGNO_MODE_OK. In 32 bit mode, require that
1923 DImode and DFmode be in even registers. For DImode, this makes some
1924 of the insns easier to write, since you don't have to worry about a
1925 DImode value in registers 3 & 4, producing a result in 4 & 5.
1926
1927 To make the code simpler, the hook now just references an
1928 array built in override_options. */
1929
1930 static bool
1931 microblaze_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
1932 {
1933 return microblaze_hard_regno_mode_ok_p[mode][regno];
1934 }
1935
1936 /* Implement TARGET_MODES_TIEABLE_P. */
1937
1938 static bool
1939 microblaze_modes_tieable_p (machine_mode mode1, machine_mode mode2)
1940 {
1941 return ((GET_MODE_CLASS (mode1) == MODE_FLOAT
1942 || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)
1943 == (GET_MODE_CLASS (mode2) == MODE_FLOAT
1944 || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
1945 }
1946
1947 /* Return true if FUNC is an interrupt function as specified
1948 by the "interrupt_handler" attribute. */
1949
1950 static int
1951 microblaze_interrupt_function_p (tree func)
1952 {
1953 tree a;
1954
1955 if (TREE_CODE (func) != FUNCTION_DECL)
1956 return 0;
1957
1958 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1959 return a != NULL_TREE;
1960 }
1961
1962 static int
1963 microblaze_fast_interrupt_function_p (tree func)
1964 {
1965 tree a;
1966
1967 if (TREE_CODE (func) != FUNCTION_DECL)
1968 return 0;
1969
1970 a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func));
1971 return a != NULL_TREE;
1972 }
1973 int
1974 microblaze_break_function_p (tree func)
1975 {
1976 tree a;
1977 if (!func)
1978 return 0;
1979 if (TREE_CODE (func) != FUNCTION_DECL)
1980 return 0;
1981
1982 a = lookup_attribute ("break_handler", DECL_ATTRIBUTES (func));
1983 return a != NULL_TREE;
1984 }
1985 /* Return true if FUNC is an interrupt function which uses
1986 normal return, indicated by the "save_volatiles" attribute. */
1987
1988 static int
1989 microblaze_save_volatiles (tree func)
1990 {
1991 tree a;
1992
1993 if (TREE_CODE (func) != FUNCTION_DECL)
1994 return 0;
1995
1996 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1997 return a != NULL_TREE;
1998 }
1999
2000 /* Return whether function is tagged with 'interrupt_handler'
2001 or 'fast_interrupt' attribute. Return true if function
2002 should use return from interrupt rather than normal
2003 function return. */
2004 int
2005 microblaze_is_interrupt_variant (void)
2006 {
2007 return (interrupt_handler || fast_interrupt);
2008 }
2009 int
2010 microblaze_is_break_handler (void)
2011 {
2012 return break_handler;
2013 }
2014
2015 /* Determine of register must be saved/restored in call. */
2016 static int
2017 microblaze_must_save_register (int regno)
2018 {
2019 if (pic_offset_table_rtx &&
2020 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
2021 return 1;
2022
2023 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
2024 return 1;
2025
2026 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
2027 return 1;
2028
2029 if (crtl->calls_eh_return
2030 && regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2031 return 1;
2032
2033 if (!crtl->is_leaf)
2034 {
2035 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2036 return 1;
2037 if ((microblaze_is_interrupt_variant () || save_volatiles) &&
2038 (regno >= 3 && regno <= 12))
2039 return 1;
2040 }
2041
2042 if (microblaze_is_interrupt_variant ())
2043 {
2044 if (df_regs_ever_live_p (regno)
2045 || regno == MB_ABI_MSR_SAVE_REG
2046 || (interrupt_handler
2047 && (regno == MB_ABI_ASM_TEMP_REGNUM
2048 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)))
2049 return 1;
2050 }
2051
2052 if (save_volatiles)
2053 {
2054 if (df_regs_ever_live_p (regno)
2055 || regno == MB_ABI_ASM_TEMP_REGNUM
2056 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
2057 return 1;
2058 }
2059
2060 if (crtl->calls_eh_return
2061 && (regno == EH_RETURN_DATA_REGNO (0)
2062 || regno == EH_RETURN_DATA_REGNO (1)))
2063 return 1;
2064
2065 return 0;
2066 }
2067
2068 /* Return the bytes needed to compute the frame pointer from the current
2069 stack pointer.
2070
2071 MicroBlaze stack frames look like:
2072
2073
2074
2075 Before call After call
2076 +-----------------------+ +-----------------------+
2077 high | | | |
2078 mem. | local variables, | | local variables, |
2079 | callee saved and | | callee saved and |
2080 | temps | | temps |
2081 +-----------------------+ +-----------------------+
2082 | arguments for called | | arguments for called |
2083 | subroutines | | subroutines |
2084 | (optional) | | (optional) |
2085 +-----------------------+ +-----------------------+
2086 | Link register | | Link register |
2087 SP->| | | |
2088 +-----------------------+ +-----------------------+
2089 | |
2090 | local variables, |
2091 | callee saved and |
2092 | temps |
2093 +-----------------------+
2094 | MSR (optional if, |
2095 | interrupt handler) |
2096 +-----------------------+
2097 | |
2098 | alloca allocations |
2099 | |
2100 +-----------------------+
2101 | |
2102 | arguments for called |
2103 | subroutines |
2104 | (optional) |
2105 | |
2106 +-----------------------+
2107 | Link register |
2108 low FP,SP->| |
2109 memory +-----------------------+
2110
2111 */
2112
2113 static HOST_WIDE_INT
2114 compute_frame_size (HOST_WIDE_INT size)
2115 {
2116 int regno;
2117 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
2118 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
2119 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
2120 int link_debug_size; /* # bytes for link register. */
2121 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
2122 long mask; /* mask of saved gp registers. */
2123
2124 interrupt_handler =
2125 microblaze_interrupt_function_p (current_function_decl);
2126 break_handler =
2127 microblaze_break_function_p (current_function_decl);
2128
2129 fast_interrupt =
2130 microblaze_fast_interrupt_function_p (current_function_decl);
2131 save_volatiles = microblaze_save_volatiles (current_function_decl);
2132 if (break_handler)
2133 interrupt_handler = break_handler;
2134
2135 gp_reg_size = 0;
2136 mask = 0;
2137 var_size = size;
2138 args_size = crtl->outgoing_args_size;
2139
2140 if ((args_size == 0) && cfun->calls_alloca)
2141 args_size = NUM_OF_ARGS * UNITS_PER_WORD;
2142
2143 total_size = var_size + args_size;
2144
2145 if (flag_pic == 2 && !TARGET_PIC_DATA_TEXT_REL)
2146 /* force setting GOT. */
2147 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
2148
2149 /* Calculate space needed for gp registers. */
2150 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2151 {
2152 if (microblaze_must_save_register (regno))
2153 {
2154
2155 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
2156 /* Don't account for link register. It is accounted specially below. */
2157 gp_reg_size += GET_MODE_SIZE (SImode);
2158
2159 mask |= (1L << (regno - GP_REG_FIRST));
2160 }
2161 }
2162
2163 total_size += gp_reg_size;
2164
2165 /* Add 4 bytes for MSR. */
2166 if (microblaze_is_interrupt_variant ())
2167 total_size += 4;
2168
2169 /* No space to be allocated for link register in leaf functions with no other
2170 stack requirements. */
2171 if (total_size == 0 && crtl->is_leaf)
2172 link_debug_size = 0;
2173 else
2174 link_debug_size = UNITS_PER_WORD;
2175
2176 total_size += link_debug_size;
2177
2178 /* Save other computed information. */
2179 current_frame_info.total_size = total_size;
2180 current_frame_info.var_size = var_size;
2181 current_frame_info.args_size = args_size;
2182 current_frame_info.gp_reg_size = gp_reg_size;
2183 current_frame_info.mask = mask;
2184 current_frame_info.initialized = reload_completed;
2185 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
2186 current_frame_info.link_debug_size = link_debug_size;
2187
2188 if (mask)
2189 /* Offset from which to callee-save GP regs. */
2190 current_frame_info.gp_offset = (total_size - gp_reg_size);
2191 else
2192 current_frame_info.gp_offset = 0;
2193
2194 /* Ok, we're done. */
2195 return total_size;
2196 }
2197
2198 /* Make sure that we're not trying to eliminate to the wrong hard frame
2199 pointer. */
2200
2201 static bool
2202 microblaze_can_eliminate (const int from, const int to)
2203 {
2204 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
2205 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
2206 || (from != RETURN_ADDRESS_POINTER_REGNUM
2207 && (to == HARD_FRAME_POINTER_REGNUM
2208 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
2209 }
2210
2211 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2212 pointer or argument pointer or the return address pointer. TO is either
2213 the stack pointer or hard frame pointer. */
2214
2215 HOST_WIDE_INT
2216 microblaze_initial_elimination_offset (int from, int to)
2217 {
2218 HOST_WIDE_INT offset;
2219
2220 switch (from)
2221 {
2222 case FRAME_POINTER_REGNUM:
2223 offset = 0;
2224 break;
2225 case ARG_POINTER_REGNUM:
2226 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
2227 offset = compute_frame_size (get_frame_size ());
2228 else
2229 gcc_unreachable ();
2230 break;
2231 case RETURN_ADDRESS_POINTER_REGNUM:
2232 if (crtl->is_leaf)
2233 offset = 0;
2234 else
2235 offset = current_frame_info.gp_offset +
2236 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
2237 break;
2238 default:
2239 gcc_unreachable ();
2240 }
2241 return offset;
2242 }
2243
2244 /* Print operands using format code.
2245
2246 The MicroBlaze specific codes are:
2247
2248 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2249 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2250 'F' op is CONST_DOUBLE, print 32 bits in hex,
2251 'd' output integer constant in decimal,
2252 'z' if the operand is 0, use $0 instead of normal operand.
2253 'D' print second register of double-word register operand.
2254 'L' print low-order register of double-word register operand.
2255 'M' print high-order register of double-word register operand.
2256 'C' print part of opcode for a branch condition.
2257 'N' print part of opcode for a branch condition, inverted.
2258 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2259 'B' print 'z' for EQ, 'n' for NE
2260 'b' print 'n' for EQ, 'z' for NE
2261 'T' print 'f' for EQ, 't' for NE
2262 't' print 't' for EQ, 'f' for NE
2263 'm' Print 1<<operand.
2264 'i' Print 'i' if MEM operand has immediate value
2265 'y' Print 'y' if MEM operand is single register
2266 'o' Print operand address+4
2267 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2268 'h' Print high word of const_double (int or float) value as hex
2269 'j' Print low word of const_double (int or float) value as hex
2270 's' Print -1 if operand is negative, 0 if positive (sign extend)
2271 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2272 '#' Print nop if the delay slot of a branch is not filled.
2273 */
2274
2275 void
2276 print_operand (FILE * file, rtx op, int letter)
2277 {
2278 register enum rtx_code code;
2279
2280 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
2281 {
2282 switch (letter)
2283 {
2284 case '?':
2285 /* Conditionally add a 'd' to indicate filled delay slot. */
2286 if (final_sequence != NULL)
2287 fputs ("d", file);
2288 break;
2289
2290 case '#':
2291 /* Conditionally add a nop in unfilled delay slot. */
2292 if (final_sequence == NULL)
2293 fputs ("nop\t\t# Unfilled delay slot\n", file);
2294 break;
2295
2296 case '@':
2297 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
2298 break;
2299
2300 default:
2301 output_operand_lossage ("unknown punctuation '%c'", letter);
2302 break;
2303 }
2304
2305 return;
2306 }
2307
2308 if (!op)
2309 {
2310 output_operand_lossage ("null pointer");
2311 return;
2312 }
2313
2314 code = GET_CODE (op);
2315
2316 if (code == SIGN_EXTEND)
2317 op = XEXP (op, 0), code = GET_CODE (op);
2318
2319 if (letter == 'C')
2320 switch (code)
2321 {
2322 case EQ:
2323 fputs ("eq", file);
2324 break;
2325 case NE:
2326 fputs ("ne", file);
2327 break;
2328 case GT:
2329 case GTU:
2330 fputs ("gt", file);
2331 break;
2332 case GE:
2333 case GEU:
2334 fputs ("ge", file);
2335 break;
2336 case LT:
2337 case LTU:
2338 fputs ("lt", file);
2339 break;
2340 case LE:
2341 case LEU:
2342 fputs ("le", file);
2343 break;
2344 default:
2345 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
2346 }
2347
2348 else if (letter == 'N')
2349 switch (code)
2350 {
2351 case EQ:
2352 fputs ("ne", file);
2353 break;
2354 case NE:
2355 fputs ("eq", file);
2356 break;
2357 case GT:
2358 case GTU:
2359 fputs ("le", file);
2360 break;
2361 case GE:
2362 case GEU:
2363 fputs ("lt", file);
2364 break;
2365 case LT:
2366 case LTU:
2367 fputs ("ge", file);
2368 break;
2369 case LE:
2370 case LEU:
2371 fputs ("gt", file);
2372 break;
2373 default:
2374 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
2375 }
2376
2377 else if (letter == 'S')
2378 {
2379 char buffer[100];
2380
2381 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
2382 assemble_name (file, buffer);
2383 }
2384
2385 /* Print 'i' for memory operands which have immediate values. */
2386 else if (letter == 'i')
2387 {
2388 if (code == MEM)
2389 {
2390 struct microblaze_address_info info;
2391
2392 if (!microblaze_classify_address
2393 (&info, XEXP (op, 0), GET_MODE (op), 1))
2394 fatal_insn ("insn contains an invalid address !", op);
2395
2396 switch (info.type)
2397 {
2398 case ADDRESS_REG:
2399 case ADDRESS_CONST_INT:
2400 case ADDRESS_SYMBOLIC:
2401 case ADDRESS_SYMBOLIC_TXT_REL:
2402 case ADDRESS_GOTOFF:
2403 case ADDRESS_TLS:
2404 fputs ("i", file);
2405 break;
2406 case ADDRESS_REG_INDEX:
2407 break;
2408 case ADDRESS_INVALID:
2409 case ADDRESS_PLT:
2410 fatal_insn ("invalid address", op);
2411 }
2412 }
2413 }
2414
2415 else if (code == REG || code == SUBREG)
2416 {
2417 register int regnum;
2418
2419 if (code == REG)
2420 regnum = REGNO (op);
2421 else
2422 regnum = true_regnum (op);
2423
2424 if ((letter == 'M' && !WORDS_BIG_ENDIAN)
2425 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
2426 regnum++;
2427
2428 fprintf (file, "%s", reg_names[regnum]);
2429 }
2430
2431 else if (code == MEM)
2432 if (letter == 'o')
2433 {
2434 rtx op4 = adjust_address (op, GET_MODE (op), 4);
2435 output_address (GET_MODE (op), XEXP (op4, 0));
2436 }
2437 else if (letter == 'y')
2438 {
2439 rtx mem_reg = XEXP (op, 0);
2440 if (GET_CODE (mem_reg) == REG)
2441 {
2442 register int regnum = REGNO (mem_reg);
2443 fprintf (file, "%s", reg_names[regnum]);
2444 }
2445 }
2446 else
2447 output_address (GET_MODE (op), XEXP (op, 0));
2448
2449 else if (letter == 'h' || letter == 'j')
2450 {
2451 long val[2];
2452 if (code == CONST_DOUBLE)
2453 {
2454 if (GET_MODE (op) == DFmode)
2455 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op), val);
2456 else
2457 {
2458 val[0] = CONST_DOUBLE_HIGH (op);
2459 val[1] = CONST_DOUBLE_LOW (op);
2460 }
2461 }
2462 else if (code == CONST_INT)
2463 {
2464 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
2465 val[1] = INTVAL (op) & 0x00000000ffffffffLL;
2466 if (val[0] == 0 && val[1] < 0)
2467 val[0] = -1;
2468
2469 }
2470 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
2471 }
2472 else if (code == CONST_DOUBLE)
2473 {
2474 if (letter == 'F')
2475 {
2476 unsigned long value_long;
2477 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op),
2478 value_long);
2479 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
2480 }
2481 else
2482 {
2483 char s[60];
2484 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
2485 fputs (s, file);
2486 }
2487 }
2488
2489 else if (code == UNSPEC)
2490 {
2491 print_operand_address (file, op);
2492 }
2493
2494 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
2495 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
2496
2497 else if (letter == 'X' && GET_CODE (op) == CONST_INT)
2498 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
2499
2500 else if (letter == 'd' && GET_CODE (op) == CONST_INT)
2501 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
2502
2503 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
2504 fputs (reg_names[GP_REG_FIRST], file);
2505
2506 else if (letter == 's' && GET_CODE (op) == CONST_INT)
2507 if (INTVAL (op) < 0)
2508 fputs ("-1", file);
2509 else
2510 fputs ("0", file);
2511
2512 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
2513 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
2514
2515 else if (letter == 'B')
2516 fputs (code == EQ ? "z" : "n", file);
2517 else if (letter == 'b')
2518 fputs (code == EQ ? "n" : "z", file);
2519 else if (letter == 'T')
2520 fputs (code == EQ ? "f" : "t", file);
2521 else if (letter == 't')
2522 fputs (code == EQ ? "t" : "f", file);
2523
2524 else if (code == CONST
2525 && ((GET_CODE (XEXP (op, 0)) == REG)
2526 || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
2527 {
2528 print_operand (file, XEXP (op, 0), letter);
2529 }
2530 else if (code == CONST
2531 && (GET_CODE (XEXP (op, 0)) == PLUS)
2532 && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
2533 && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
2534 {
2535 print_operand_address (file, XEXP (op, 0));
2536 }
2537 else if (letter == 'm')
2538 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
2539 else
2540 output_addr_const (file, op);
2541 }
2542
2543 /* A C compound statement to output to stdio stream STREAM the
2544 assembler syntax for an instruction operand that is a memory
2545 reference whose address is ADDR. ADDR is an RTL expression.
2546
2547 Possible address classifications and output formats are,
2548
2549 ADDRESS_REG "%0, r0"
2550
2551 ADDRESS_REG with non-zero "%0, <addr_const>"
2552 offset
2553
2554 ADDRESS_REG_INDEX "rA, RB"
2555 (if rA is r0, rA and rB are swapped)
2556
2557 ADDRESS_CONST_INT "r0, <addr_const>"
2558
2559 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2560 (rBase is a base register suitable for the
2561 symbol's type)
2562 */
2563
2564 void
2565 print_operand_address (FILE * file, rtx addr)
2566 {
2567 struct microblaze_address_info info;
2568 enum microblaze_address_type type;
2569 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 2))
2570 fatal_insn ("insn contains an invalid address !", addr);
2571
2572 type = info.type;
2573 switch (info.type)
2574 {
2575 case ADDRESS_REG:
2576 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2577 output_addr_const (file, info.offset);
2578 break;
2579 case ADDRESS_REG_INDEX:
2580 if (REGNO (info.regA) == 0)
2581 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2582 congestion. */
2583 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2584 reg_names[REGNO (info.regA)]);
2585 else if (REGNO (info.regB) != 0)
2586 /* This is a silly swap to help Dhrystone. */
2587 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2588 reg_names[REGNO (info.regA)]);
2589 break;
2590 case ADDRESS_CONST_INT:
2591 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2592 output_addr_const (file, info.offset);
2593 break;
2594 case ADDRESS_SYMBOLIC:
2595 case ADDRESS_SYMBOLIC_TXT_REL:
2596 case ADDRESS_GOTOFF:
2597 case ADDRESS_PLT:
2598 case ADDRESS_TLS:
2599 if (info.regA)
2600 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2601 output_addr_const (file, info.symbol);
2602 if (type == ADDRESS_GOTOFF)
2603 {
2604 fputs ("@GOT", file);
2605 }
2606 else if (type == ADDRESS_PLT)
2607 {
2608 fputs ("@PLT", file);
2609 }
2610 else if (type == ADDRESS_SYMBOLIC_TXT_REL)
2611 {
2612 if (info.offset != NULL && CONST_INT_P (info.offset)
2613 && INTVAL (info.offset) > 0)
2614 {
2615 fprintf (file, "+");
2616 output_addr_const (file, info.offset);
2617 }
2618 fputs ("@TXTREL", file);
2619 }
2620 else if (type == ADDRESS_TLS)
2621 {
2622 switch (info.tls_type)
2623 {
2624 case TLS_GD:
2625 fputs ("@TLSGD", file);
2626 break;
2627 case TLS_LDM:
2628 fputs ("@TLSLDM", file);
2629 break;
2630 case TLS_DTPREL:
2631 fputs ("@TLSDTPREL", file);
2632 break;
2633 default :
2634 abort();
2635 break;
2636 }
2637 }
2638 break;
2639 case ADDRESS_INVALID:
2640 fatal_insn ("invalid address", addr);
2641 break;
2642 }
2643 }
2644
2645 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2646 is used, so that we don't emit an .extern for it in
2647 microblaze_asm_file_end. */
2648
2649 void
2650 microblaze_declare_object (FILE * stream, const char *name,
2651 const char *section, const char *fmt, int size)
2652 {
2653
2654 fputs (section, stream);
2655 assemble_name (stream, name);
2656 fprintf (stream, fmt, size);
2657 }
2658
2659 /* Common code to emit the insns (or to write the instructions to a file)
2660 to save/restore registers.
2661
2662 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2663 is not modified within save_restore_insns. */
2664
2665 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2666
2667 /* Save or restore instructions based on whether this is the prologue or
2668 epilogue. prologue is 1 for the prologue. */
2669 static void
2670 save_restore_insns (int prologue)
2671 {
2672 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2673 0, isr_mem_rtx = 0;
2674 rtx isr_msr_rtx = 0, insn;
2675 long mask = current_frame_info.mask;
2676 HOST_WIDE_INT gp_offset;
2677 int regno;
2678
2679 if (frame_pointer_needed
2680 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2681 gcc_unreachable ();
2682
2683 if (mask == 0)
2684 return;
2685
2686 /* Save registers starting from high to low. The debuggers prefer at least
2687 the return register be stored at func+4, and also it allows us not to
2688 need a nop in the epilog if at least one register is reloaded in
2689 addition to return address. */
2690
2691 /* Pick which pointer to use as a base register. For small frames, just
2692 use the stack pointer. Otherwise, use a temporary register. Save 2
2693 cycles if the save area is near the end of a large frame, by reusing
2694 the constant created in the prologue/epilogue to adjust the stack
2695 frame. */
2696
2697 gp_offset = current_frame_info.gp_offset;
2698
2699 gcc_assert (gp_offset > 0);
2700
2701 base_reg_rtx = stack_pointer_rtx;
2702
2703 /* For interrupt_handlers, need to save/restore the MSR. */
2704 if (microblaze_is_interrupt_variant ())
2705 {
2706 isr_mem_rtx = gen_rtx_MEM (SImode,
2707 gen_rtx_PLUS (Pmode, base_reg_rtx,
2708 GEN_INT (current_frame_info.
2709 gp_offset -
2710 UNITS_PER_WORD)));
2711
2712 /* Do not optimize in flow analysis. */
2713 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2714 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2715 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2716 }
2717
2718 if (microblaze_is_interrupt_variant () && !prologue)
2719 {
2720 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2721 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2722 /* Do not optimize in flow analysis. */
2723 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2724 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2725 }
2726
2727 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2728 {
2729 if (BITSET_P (mask, regno - GP_REG_FIRST))
2730 {
2731 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2732 /* Don't handle here. Already handled as the first register. */
2733 continue;
2734
2735 reg_rtx = gen_rtx_REG (SImode, regno);
2736 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2737 mem_rtx = gen_rtx_MEM (SImode, insn);
2738 if (microblaze_is_interrupt_variant () || save_volatiles)
2739 /* Do not optimize in flow analysis. */
2740 MEM_VOLATILE_P (mem_rtx) = 1;
2741
2742 if (prologue)
2743 {
2744 insn = emit_move_insn (mem_rtx, reg_rtx);
2745 RTX_FRAME_RELATED_P (insn) = 1;
2746 }
2747 else
2748 {
2749 insn = emit_move_insn (reg_rtx, mem_rtx);
2750 }
2751
2752 gp_offset += GET_MODE_SIZE (SImode);
2753 }
2754 }
2755
2756 if (microblaze_is_interrupt_variant () && prologue)
2757 {
2758 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2759 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2760
2761 /* Do not optimize in flow analysis. */
2762 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2763 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2764 }
2765
2766 /* Done saving and restoring */
2767 }
2768
2769
2770 /* Set up the stack and frame (if desired) for the function. */
2771 static void
2772 microblaze_function_prologue (FILE * file)
2773 {
2774 const char *fnname;
2775 long fsiz = current_frame_info.total_size;
2776
2777 /* Get the function name the same way that toplev.c does before calling
2778 assemble_start_function. This is needed so that the name used here
2779 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2780 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2781 if (!flag_inhibit_size_directive)
2782 {
2783 fputs ("\t.ent\t", file);
2784 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2785 fputs ("_interrupt_handler", file);
2786 else if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2787 fputs ("_break_handler", file);
2788 else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname))
2789 fputs ("_fast_interrupt", file);
2790 else
2791 assemble_name (file, fnname);
2792 fputs ("\n", file);
2793 if (!microblaze_is_interrupt_variant ())
2794 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2795 }
2796
2797 assemble_name (file, fnname);
2798 fputs (":\n", file);
2799
2800 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2801 fputs ("_interrupt_handler:\n", file);
2802 if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2803 fputs ("_break_handler:\n", file);
2804 if (!flag_inhibit_size_directive)
2805 {
2806 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2807 fprintf (file,
2808 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2809 (reg_names[(frame_pointer_needed)
2810 ? HARD_FRAME_POINTER_REGNUM :
2811 STACK_POINTER_REGNUM]), fsiz,
2812 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2813 current_frame_info.var_size, current_frame_info.num_gp,
2814 (int) crtl->outgoing_args_size);
2815 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2816 }
2817 }
2818
2819 /* Output extra assembler code at the end of a prologue. */
2820 static void
2821 microblaze_function_end_prologue (FILE * file)
2822 {
2823 if (TARGET_STACK_CHECK)
2824 {
2825 fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2826 fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2827 fprintf (file, "cmpu\tr18,r1,r18\n\t");
2828 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2829 fprintf (file, "# Stack Check Stub -- End.\n");
2830 }
2831 }
2832
2833 static void
2834 microblaze_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
2835 {
2836 section *s;
2837
2838 if (priority != DEFAULT_INIT_PRIORITY)
2839 {
2840 char buf[18];
2841 sprintf (buf, "%s.%.5u",
2842 is_ctor ? ".ctors" : ".dtors",
2843 MAX_INIT_PRIORITY - priority);
2844 s = get_section (buf, SECTION_WRITE, NULL_TREE);
2845 }
2846 else if (is_ctor)
2847 s = ctors_section;
2848 else
2849 s = dtors_section;
2850
2851 switch_to_section (s);
2852 assemble_align (POINTER_SIZE);
2853 fputs ("\t.word\t", asm_out_file);
2854 output_addr_const (asm_out_file, symbol);
2855 fputs ("\n", asm_out_file);
2856 }
2857
2858 /* Add a function to the list of static constructors. */
2859
2860 static void
2861 microblaze_elf_asm_constructor (rtx symbol, int priority)
2862 {
2863 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/true);
2864 }
2865
2866 /* Add a function to the list of static destructors. */
2867
2868 static void
2869 microblaze_elf_asm_destructor (rtx symbol, int priority)
2870 {
2871 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false);
2872 }
2873
2874 /* Expand the prologue into a bunch of separate insns. */
2875
2876 void
2877 microblaze_expand_prologue (void)
2878 {
2879 int regno;
2880 HOST_WIDE_INT fsiz;
2881 const char *arg_name = 0;
2882 tree fndecl = current_function_decl;
2883 tree fntype = TREE_TYPE (fndecl);
2884 tree fnargs = DECL_ARGUMENTS (fndecl);
2885 rtx next_arg_reg;
2886 int i;
2887 tree next_arg;
2888 tree cur_arg;
2889 CUMULATIVE_ARGS args_so_far_v;
2890 cumulative_args_t args_so_far;
2891 rtx mem_rtx, reg_rtx;
2892
2893 /* If struct value address is treated as the first argument, make it so. */
2894 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2895 && !cfun->returns_pcc_struct)
2896 {
2897 tree type = build_pointer_type (fntype);
2898 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2899 NULL_TREE, type);
2900
2901 DECL_ARG_TYPE (function_result_decl) = type;
2902 TREE_CHAIN (function_result_decl) = fnargs;
2903 fnargs = function_result_decl;
2904 }
2905
2906 /* Determine the last argument, and get its name. */
2907
2908 INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
2909 args_so_far = pack_cumulative_args (&args_so_far_v);
2910 regno = GP_ARG_FIRST;
2911
2912 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2913 {
2914 tree passed_type = DECL_ARG_TYPE (cur_arg);
2915 machine_mode passed_mode = TYPE_MODE (passed_type);
2916 rtx entry_parm;
2917
2918 if (TREE_ADDRESSABLE (passed_type))
2919 {
2920 passed_type = build_pointer_type (passed_type);
2921 passed_mode = Pmode;
2922 }
2923
2924 entry_parm = targetm.calls.function_arg (args_so_far, passed_mode,
2925 passed_type, true);
2926
2927 if (entry_parm)
2928 {
2929 int words;
2930
2931 /* passed in a register, so will get homed automatically. */
2932 if (GET_MODE (entry_parm) == BLKmode)
2933 words = (int_size_in_bytes (passed_type) + 3) / 4;
2934 else
2935 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2936
2937 regno = REGNO (entry_parm) + words - 1;
2938 }
2939 else
2940 {
2941 regno = GP_ARG_LAST + 1;
2942 break;
2943 }
2944
2945 targetm.calls.function_arg_advance (args_so_far, passed_mode,
2946 passed_type, true);
2947
2948 next_arg = TREE_CHAIN (cur_arg);
2949 if (next_arg == 0)
2950 {
2951 if (DECL_NAME (cur_arg))
2952 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2953
2954 break;
2955 }
2956 }
2957
2958 /* Split parallel insn into a sequence of insns. */
2959
2960 next_arg_reg = targetm.calls.function_arg (args_so_far, VOIDmode,
2961 void_type_node, true);
2962 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2963 {
2964 rtvec adjust = XVEC (next_arg_reg, 0);
2965 int num = GET_NUM_ELEM (adjust);
2966
2967 for (i = 0; i < num; i++)
2968 {
2969 rtx pattern = RTVEC_ELT (adjust, i);
2970 emit_insn (pattern);
2971 }
2972 }
2973
2974 fsiz = compute_frame_size (get_frame_size ());
2975
2976 if (flag_stack_usage_info)
2977 current_function_static_stack_size = fsiz;
2978
2979 /* If this function is a varargs function, store any registers that
2980 would normally hold arguments ($5 - $10) on the stack. */
2981 if (((TYPE_ARG_TYPES (fntype) != 0
2982 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2983 != void_type_node))
2984 || (arg_name != 0
2985 && ((arg_name[0] == '_'
2986 && strcmp (arg_name, "__builtin_va_alist") == 0)
2987 || (arg_name[0] == 'v'
2988 && strcmp (arg_name, "va_alist") == 0)))))
2989 {
2990 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2991 rtx ptr = stack_pointer_rtx;
2992
2993 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2994 for (; regno <= GP_ARG_LAST; regno++)
2995 {
2996 if (offset != 0)
2997 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2998 emit_move_insn (gen_rtx_MEM (SImode, ptr),
2999 gen_rtx_REG (SImode, regno));
3000
3001 offset += GET_MODE_SIZE (SImode);
3002 }
3003 }
3004
3005 if (fsiz > 0)
3006 {
3007 rtx fsiz_rtx = GEN_INT (fsiz);
3008
3009 rtx_insn *insn = NULL;
3010 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
3011 fsiz_rtx));
3012 if (insn)
3013 RTX_FRAME_RELATED_P (insn) = 1;
3014
3015 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
3016 if (!crtl->is_leaf || interrupt_handler)
3017 {
3018 mem_rtx = gen_rtx_MEM (SImode,
3019 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3020 const0_rtx));
3021
3022 if (interrupt_handler)
3023 /* Do not optimize in flow analysis. */
3024 MEM_VOLATILE_P (mem_rtx) = 1;
3025
3026 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
3027 insn = emit_move_insn (mem_rtx, reg_rtx);
3028 RTX_FRAME_RELATED_P (insn) = 1;
3029 }
3030
3031 /* _save_ registers for prologue. */
3032 save_restore_insns (1);
3033
3034 if (frame_pointer_needed)
3035 {
3036 rtx_insn *insn = 0;
3037
3038 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
3039 stack_pointer_rtx));
3040
3041 if (insn)
3042 RTX_FRAME_RELATED_P (insn) = 1;
3043 }
3044 }
3045
3046 if ((flag_pic == 2 || TLS_NEEDS_GOT )
3047 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
3048 {
3049 if ((flag_pic == 2 && !TARGET_PIC_DATA_TEXT_REL) || TLS_NEEDS_GOT)
3050 {
3051 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
3052 /* setting GOT. */
3053 emit_insn (gen_set_got (pic_offset_table_rtx));
3054 }
3055 else
3056 {
3057 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
3058 /* setting start of text. */
3059 emit_insn (gen_set_text (pic_offset_table_rtx));
3060 }
3061 }
3062
3063 /* If we are profiling, make sure no instructions are scheduled before
3064 the call to mcount. */
3065
3066 if (profile_flag)
3067 emit_insn (gen_blockage ());
3068 }
3069
3070 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
3071
3072 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
3073 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
3074
3075 static void
3076 microblaze_function_epilogue (FILE *file)
3077 {
3078 const char *fnname;
3079
3080 /* Get the function name the same way that toplev.c does before calling
3081 assemble_start_function. This is needed so that the name used here
3082 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
3083 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
3084
3085 if (!flag_inhibit_size_directive)
3086 {
3087 fputs ("\t.end\t", file);
3088 if (interrupt_handler && !break_handler)
3089 fputs ("_interrupt_handler", file);
3090 else if (break_handler)
3091 fputs ("_break_handler", file);
3092 else
3093 assemble_name (file, fnname);
3094 fputs ("\n", file);
3095 }
3096
3097 /* Reset state info for each function. */
3098 current_frame_info = zero_frame_info;
3099
3100 /* Restore the output file if optimizing the GP (optimizing the GP causes
3101 the text to be diverted to a tempfile, so that data decls come before
3102 references to the data). */
3103 }
3104
3105 /* Expand the epilogue into a bunch of separate insns. */
3106
3107 void
3108 microblaze_expand_epilogue (void)
3109 {
3110 HOST_WIDE_INT fsiz = current_frame_info.total_size;
3111 rtx fsiz_rtx = GEN_INT (fsiz);
3112 rtx reg_rtx;
3113 rtx mem_rtx;
3114
3115 /* In case of interrupt handlers use addki instead of addi for changing the
3116 stack pointer value. */
3117
3118 if (microblaze_can_use_return_insn ())
3119 {
3120 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
3121 GP_REG_FIRST +
3122 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3123 return;
3124 }
3125
3126 if (fsiz > 0)
3127 {
3128 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3129 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3130 a load-use stall cycle :) This is also important to handle alloca.
3131 (See comments for if (frame_pointer_needed) below. */
3132
3133 if (!crtl->is_leaf || interrupt_handler)
3134 {
3135 mem_rtx =
3136 gen_rtx_MEM (SImode,
3137 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
3138 if (interrupt_handler)
3139 /* Do not optimize in flow analysis. */
3140 MEM_VOLATILE_P (mem_rtx) = 1;
3141 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
3142 emit_move_insn (reg_rtx, mem_rtx);
3143 }
3144
3145 /* It is important that this is done after we restore the return address
3146 register (above). When alloca is used, we want to restore the
3147 sub-routine return address only from the current stack top and not
3148 from the frame pointer (which we restore below). (frame_pointer + 0)
3149 might have been over-written since alloca allocates memory on the
3150 current stack. */
3151 if (frame_pointer_needed)
3152 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
3153
3154 /* _restore_ registers for epilogue. */
3155 save_restore_insns (0);
3156 emit_insn (gen_blockage ());
3157 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
3158 }
3159
3160 if (crtl->calls_eh_return)
3161 emit_insn (gen_addsi3 (stack_pointer_rtx,
3162 stack_pointer_rtx,
3163 gen_raw_REG (SImode,
3164 MB_EH_STACKADJ_REGNUM)));
3165
3166 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
3167 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3168 }
3169
3170
3171 /* Return nonzero if this function is known to have a null epilogue.
3172 This allows the optimizer to omit jumps to jumps if no stack
3173 was created. */
3174
3175 int
3176 microblaze_can_use_return_insn (void)
3177 {
3178 if (!reload_completed)
3179 return 0;
3180
3181 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
3182 return 0;
3183
3184 if (current_frame_info.initialized)
3185 return current_frame_info.total_size == 0;
3186
3187 return compute_frame_size (get_frame_size ()) == 0;
3188 }
3189
3190 /* Implement TARGET_SECONDARY_RELOAD. */
3191
3192 static reg_class_t
3193 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
3194 reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED,
3195 secondary_reload_info *sri ATTRIBUTE_UNUSED)
3196 {
3197 if (rclass == ST_REGS)
3198 return GR_REGS;
3199
3200 return NO_REGS;
3201 }
3202
3203 static void
3204 microblaze_globalize_label (FILE * stream, const char *name)
3205 {
3206 fputs ("\t.globl\t", stream);
3207 if (microblaze_is_interrupt_variant ())
3208 {
3209 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
3210 fputs (INTERRUPT_HANDLER_NAME, stream);
3211 else if (break_handler && strcmp (name, BREAK_HANDLER_NAME))
3212 fputs (BREAK_HANDLER_NAME, stream);
3213 else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME))
3214 fputs (FAST_INTERRUPT_NAME, stream);
3215 fputs ("\n\t.globl\t", stream);
3216 }
3217 assemble_name (stream, name);
3218 fputs ("\n", stream);
3219 }
3220
3221 /* Returns true if decl should be placed into a "small data" section. */
3222 static bool
3223 microblaze_elf_in_small_data_p (const_tree decl)
3224 {
3225 HOST_WIDE_INT size;
3226
3227 if (!TARGET_XLGPOPT)
3228 return false;
3229
3230 /* We want to merge strings, so we never consider them small data. */
3231 if (TREE_CODE (decl) == STRING_CST)
3232 return false;
3233
3234 /* Functions are never in the small data area. */
3235 if (TREE_CODE (decl) == FUNCTION_DECL)
3236 return false;
3237
3238 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
3239 {
3240 const char *section = DECL_SECTION_NAME (decl);
3241 if (strcmp (section, ".sdata") == 0
3242 || strcmp (section, ".sdata2") == 0
3243 || strcmp (section, ".sbss") == 0
3244 || strcmp (section, ".sbss2") == 0)
3245 return true;
3246 }
3247
3248 size = int_size_in_bytes (TREE_TYPE (decl));
3249
3250 return (size > 0 && size <= microblaze_section_threshold);
3251 }
3252
3253 /* We need to disable address diff vectors in
3254 case of pic data text relative mode. */
3255
3256 static bool
3257 microblaze_gen_pic_addr_dif_vec (void)
3258 {
3259 return (flag_pic && !TARGET_PIC_DATA_TEXT_REL);
3260 }
3261
3262 static section *
3263 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
3264 {
3265 switch (categorize_decl_for_section (decl, reloc))
3266 {
3267 case SECCAT_RODATA_MERGE_STR:
3268 case SECCAT_RODATA_MERGE_STR_INIT:
3269 /* MB binutils have various issues with mergeable string sections and
3270 relaxation/relocation. Currently, turning mergeable sections
3271 into regular readonly sections. */
3272
3273 return readonly_data_section;
3274 default:
3275 return default_elf_select_section (decl, reloc, align);
3276 }
3277 }
3278
3279 /*
3280 Encode info about sections into the RTL based on a symbol's declaration.
3281 The default definition of this hook, default_encode_section_info in
3282 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3283
3284 static void
3285 microblaze_encode_section_info (tree decl, rtx rtl, int first)
3286 {
3287 default_encode_section_info (decl, rtl, first);
3288 }
3289
3290 static rtx
3291 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED, rtx op)
3292 {
3293 rtx result;
3294 bool isFunc = (GET_CODE (op) == SYMBOL_REF
3295 && (SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_FUNCTION));
3296 result = (!TARGET_PIC_DATA_TEXT_REL)
3297 ? gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF)
3298 : gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_TEXT);
3299 result = gen_rtx_CONST (Pmode, result);
3300 result = (TARGET_PIC_DATA_TEXT_REL && isFunc)
3301 ? gen_rtx_PLUS (Pmode, gen_raw_REG (Pmode,
3302 get_base_reg (op)), result)
3303 : gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
3304 result = (!TARGET_PIC_DATA_TEXT_REL)
3305 ? gen_const_mem (Pmode, result) : result;
3306
3307 return result;
3308 }
3309
3310 static void
3311 microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
3312 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
3313 tree function)
3314 {
3315 rtx this_rtx, funexp;
3316 rtx_insn *insn;
3317
3318 reload_completed = 1;
3319 epilogue_completed = 1;
3320
3321 /* Mark the end of the (empty) prologue. */
3322 emit_note (NOTE_INSN_PROLOGUE_END);
3323
3324 /* Find the "this" pointer. If the function returns a structure,
3325 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3326 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
3327 this_rtx = gen_rtx_REG (Pmode, (MB_ABI_FIRST_ARG_REGNUM + 1));
3328 else
3329 this_rtx = gen_rtx_REG (Pmode, MB_ABI_FIRST_ARG_REGNUM);
3330
3331 /* Apply the constant offset, if required. */
3332 if (delta)
3333 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
3334
3335 /* Apply the offset from the vtable, if required. */
3336 if (vcall_offset)
3337 {
3338 rtx vcall_offset_rtx = GEN_INT (vcall_offset);
3339 rtx temp1 = gen_rtx_REG (Pmode, MB_ABI_TEMP1_REGNUM);
3340
3341 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
3342
3343 rtx loc = gen_rtx_PLUS (Pmode, temp1, vcall_offset_rtx);
3344 emit_move_insn (temp1, gen_rtx_MEM (Pmode, loc));
3345
3346 emit_insn (gen_addsi3 (this_rtx, this_rtx, temp1));
3347 }
3348
3349 /* Generate a tail call to the target function. */
3350 if (!TREE_USED (function))
3351 {
3352 assemble_external (function);
3353 TREE_USED (function) = 1;
3354 }
3355
3356 funexp = XEXP (DECL_RTL (function), 0);
3357 rtx temp2 = gen_rtx_REG (Pmode, MB_ABI_TEMP2_REGNUM);
3358
3359 if (flag_pic)
3360 emit_move_insn (temp2, expand_pic_symbol_ref (Pmode, funexp));
3361 else
3362 emit_move_insn (temp2, funexp);
3363
3364 emit_insn (gen_indirect_jump (temp2));
3365
3366 /* Run just enough of rest_of_compilation. This sequence was
3367 "borrowed" from rs6000.c. */
3368 insn = get_insns ();
3369 shorten_branches (insn);
3370 final_start_function (insn, file, 1);
3371 final (insn, file, 1);
3372 final_end_function ();
3373
3374 reload_completed = 0;
3375 epilogue_completed = 0;
3376 }
3377
3378 bool
3379 microblaze_expand_move (machine_mode mode, rtx operands[])
3380 {
3381 rtx op0, op1;
3382
3383 op0 = operands[0];
3384 op1 = operands[1];
3385
3386 if (!register_operand (op0, SImode)
3387 && !register_operand (op1, SImode)
3388 && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
3389 {
3390 rtx temp = force_reg (SImode, op1);
3391 emit_move_insn (op0, temp);
3392 return true;
3393 }
3394 /* If operands[1] is a constant address invalid for pic, then we need to
3395 handle it just like LEGITIMIZE_ADDRESS does. */
3396 if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
3397 {
3398 rtx result;
3399 if (microblaze_tls_symbol_p(op1))
3400 {
3401 result = microblaze_legitimize_tls_address (op1, NULL_RTX);
3402 emit_move_insn (op0, result);
3403 return true;
3404 }
3405 else if (flag_pic)
3406 {
3407 if (reload_in_progress)
3408 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3409 result = expand_pic_symbol_ref (mode, op1);
3410
3411 if (TARGET_PIC_DATA_TEXT_REL && GET_CODE (op0) == REG
3412 && REGNO (op0) >= FIRST_PSEUDO_REGISTER)
3413 result = force_reg (SImode, result);
3414
3415 emit_move_insn (op0, result);
3416 return true;
3417 }
3418 }
3419 if (GET_CODE (op1) == PLUS && GET_CODE (XEXP (op1,1)) == CONST)
3420 {
3421 rtx p0, p1, result, temp;
3422
3423 p0 = XEXP (XEXP (op1,1), 0);
3424
3425 if (GET_CODE (p0) == PLUS)
3426 {
3427 p1 = XEXP (p0, 1);
3428 p0 = XEXP (p0, 0);
3429 }
3430
3431 if (GET_CODE (p0) == UNSPEC && GET_CODE (p1) == CONST_INT
3432 && flag_pic && TARGET_PIC_DATA_TEXT_REL)
3433 {
3434 result = gen_rtx_CONST (Pmode, p0);
3435 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
3436 temp = force_reg (SImode, result);
3437 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, p1));
3438 return true;
3439 }
3440 }
3441 /* Handle Case of (const (plus symbol const_int)). */
3442 if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
3443 {
3444 rtx p0, p1;
3445
3446 p0 = XEXP (XEXP (op1, 0), 0);
3447 p1 = XEXP (XEXP (op1, 0), 1);
3448
3449 if ((GET_CODE (p1) == CONST_INT)
3450 && ((GET_CODE (p0) == UNSPEC)
3451 || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3452 && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
3453 || !SMALL_INT (p1)))))
3454 {
3455 rtx temp = force_reg (SImode, p0);
3456 rtx temp2 = p1;
3457
3458 if (flag_pic && reload_in_progress)
3459 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3460 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
3461 return true;
3462 }
3463 }
3464 return false;
3465 }
3466
3467 /* Expand shift operations. */
3468 int
3469 microblaze_expand_shift (rtx operands[])
3470 {
3471 gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
3472 || (GET_CODE (operands[2]) == REG)
3473 || (GET_CODE (operands[2]) == SUBREG));
3474
3475 /* Shift by one -- generate pattern. */
3476 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
3477 return 0;
3478
3479 /* Have barrel shifter and shift > 1: use it. */
3480 if (TARGET_BARREL_SHIFT)
3481 return 0;
3482
3483 gcc_assert ((GET_CODE (operands[0]) == REG)
3484 || (GET_CODE (operands[0]) == SUBREG)
3485 || (GET_CODE (operands[1]) == REG)
3486 || (GET_CODE (operands[1]) == SUBREG));
3487
3488 /* Shift by zero -- copy regs if necessary. */
3489 if (operands[2] == const0_rtx
3490 && !rtx_equal_p (operands[0], operands[1]))
3491 {
3492 emit_insn (gen_movsi (operands[0], operands[1]));
3493 return 1;
3494 }
3495
3496 return 0;
3497 }
3498
3499 /* Return an RTX indicating where the return address to the
3500 calling function can be found. */
3501 rtx
3502 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3503 {
3504 if (count != 0)
3505 return NULL_RTX;
3506
3507 return get_hard_reg_initial_val (Pmode,
3508 MB_ABI_SUB_RETURN_ADDR_REGNUM);
3509 }
3510
3511 void
3512 microblaze_eh_return (rtx op0)
3513 {
3514 emit_insn (gen_movsi (gen_rtx_MEM (Pmode, stack_pointer_rtx), op0));
3515 }
3516
3517 /* Queue an .ident string in the queue of top-level asm statements.
3518 If the string size is below the threshold, put it into .sdata2.
3519 If the front-end is done, we must be being called from toplev.c.
3520 In that case, do nothing. */
3521 void
3522 microblaze_asm_output_ident (const char *string)
3523 {
3524 const char *section_asm_op;
3525 int size;
3526 char *buf;
3527
3528 if (symtab->state != PARSING)
3529 return;
3530
3531 size = strlen (string) + 1;
3532 if (size <= microblaze_section_threshold)
3533 section_asm_op = SDATA2_SECTION_ASM_OP;
3534 else
3535 section_asm_op = READONLY_DATA_SECTION_ASM_OP;
3536
3537 buf = ACONCAT (("\t.pushsection", section_asm_op,
3538 "\n\t.ascii \"", string, "\\0\"\n",
3539 "\t.popsection\n", NULL));
3540 symtab->finalize_toplevel_asm (build_string (strlen (buf), buf));
3541 }
3542
3543 static void
3544 microblaze_elf_asm_init_sections (void)
3545 {
3546 sdata2_section
3547 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
3548 SDATA2_SECTION_ASM_OP);
3549 }
3550
3551 /* Generate assembler code for constant parts of a trampoline. */
3552
3553 static void
3554 microblaze_asm_trampoline_template (FILE *f)
3555 {
3556 fprintf (f, "\tmfs r18, rpc\n");
3557 fprintf (f, "\tlwi r3, r18, 16\n");
3558 fprintf (f, "\tlwi r18, r18, 20\n");
3559 fprintf (f, "\tbra r18\n");
3560 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3561 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3562 }
3563
3564 /* Implement TARGET_TRAMPOLINE_INIT. */
3565
3566 static void
3567 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
3568 {
3569 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
3570 rtx mem;
3571
3572 emit_block_move (m_tramp, assemble_trampoline_template (),
3573 GEN_INT (6*UNITS_PER_WORD), BLOCK_OP_NORMAL);
3574
3575 mem = adjust_address (m_tramp, SImode, 16);
3576 emit_move_insn (mem, chain_value);
3577 mem = adjust_address (m_tramp, SImode, 20);
3578 emit_move_insn (mem, fnaddr);
3579 }
3580 \f
3581 /* Generate conditional branch -- first, generate test condition,
3582 second, generate correct branch instruction. */
3583
3584 void
3585 microblaze_expand_conditional_branch (machine_mode mode, rtx operands[])
3586 {
3587 enum rtx_code code = GET_CODE (operands[0]);
3588 rtx cmp_op0 = operands[1];
3589 rtx cmp_op1 = operands[2];
3590 rtx label1 = operands[3];
3591 rtx comp_reg = gen_reg_rtx (SImode);
3592 rtx condition;
3593
3594 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
3595
3596 /* If comparing against zero, just test source reg. */
3597 if (cmp_op1 == const0_rtx)
3598 {
3599 comp_reg = cmp_op0;
3600 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3601 emit_jump_insn (gen_condjump (condition, label1));
3602 }
3603
3604 else if (code == EQ || code == NE)
3605 {
3606 /* Use xor for equal/not-equal comparison. */
3607 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
3608 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3609 emit_jump_insn (gen_condjump (condition, label1));
3610 }
3611 else
3612 {
3613 /* Generate compare and branch in single instruction. */
3614 cmp_op1 = force_reg (mode, cmp_op1);
3615 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3616 emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1));
3617 }
3618 }
3619
3620 void
3621 microblaze_expand_conditional_branch_reg (machine_mode mode, rtx operands[])
3622 {
3623 enum rtx_code code = GET_CODE (operands[0]);
3624 rtx cmp_op0 = operands[1];
3625 rtx cmp_op1 = operands[2];
3626 rtx label1 = operands[3];
3627 rtx comp_reg = gen_reg_rtx (SImode);
3628 rtx condition;
3629
3630 gcc_assert ((GET_CODE (cmp_op0) == REG)
3631 || (GET_CODE (cmp_op0) == SUBREG));
3632
3633 /* If comparing against zero, just test source reg. */
3634 if (cmp_op1 == const0_rtx)
3635 {
3636 comp_reg = cmp_op0;
3637 condition = gen_rtx_fmt_ee (signed_condition (code),
3638 SImode, comp_reg, const0_rtx);
3639 emit_jump_insn (gen_condjump (condition, label1));
3640 }
3641 else if (code == EQ)
3642 {
3643 emit_insn (gen_seq_internal_pat (comp_reg,
3644 cmp_op0, cmp_op1));
3645 condition = gen_rtx_EQ (SImode, comp_reg, const0_rtx);
3646 emit_jump_insn (gen_condjump (condition, label1));
3647 }
3648 else if (code == NE)
3649 {
3650 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0,
3651 cmp_op1));
3652 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3653 emit_jump_insn (gen_condjump (condition, label1));
3654 }
3655 else
3656 {
3657 /* Generate compare and branch in single instruction. */
3658 cmp_op1 = force_reg (mode, cmp_op1);
3659 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3660 emit_jump_insn (gen_branch_compare (condition, cmp_op0,
3661 cmp_op1, label1));
3662 }
3663 }
3664
3665 void
3666 microblaze_expand_conditional_branch_sf (rtx operands[])
3667 {
3668 rtx condition;
3669 rtx cmp_op0 = XEXP (operands[0], 0);
3670 rtx cmp_op1 = XEXP (operands[0], 1);
3671 rtx comp_reg = gen_reg_rtx (SImode);
3672
3673 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
3674 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3675 emit_jump_insn (gen_condjump (condition, operands[3]));
3676 }
3677
3678 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3679
3680 static bool
3681 microblaze_frame_pointer_required (void)
3682 {
3683 /* If the function contains dynamic stack allocations, we need to
3684 use the frame pointer to access the static parts of the frame. */
3685 if (cfun->calls_alloca)
3686 return true;
3687 return false;
3688 }
3689
3690 void
3691 microblaze_expand_divide (rtx operands[])
3692 {
3693 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3694
3695 rtx regt1 = gen_reg_rtx (SImode);
3696 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
3697 rtx regqi = gen_reg_rtx (QImode);
3698 rtx_code_label *div_label = gen_label_rtx ();
3699 rtx_code_label *div_end_label = gen_label_rtx ();
3700 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
3701 rtx mem_rtx;
3702 rtx ret;
3703 rtx_insn *jump, *cjump, *insn;
3704
3705 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
3706 cjump = emit_jump_insn_after (gen_cbranchsi4 (
3707 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
3708 regt1, GEN_INT (15), div_label), insn);
3709 LABEL_NUSES (div_label) = 1;
3710 JUMP_LABEL (cjump) = div_label;
3711 emit_insn (gen_rtx_CLOBBER (SImode, reg18));
3712
3713 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
3714 emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
3715 mem_rtx = gen_rtx_MEM (QImode,
3716 gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
3717
3718 insn = emit_insn (gen_movqi (regqi, mem_rtx));
3719 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
3720 jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
3721 JUMP_LABEL (jump) = div_end_label;
3722 LABEL_NUSES (div_end_label) = 1;
3723 emit_barrier ();
3724
3725 emit_label (div_label);
3726 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
3727 operands[0], LCT_NORMAL,
3728 GET_MODE (operands[0]),
3729 operands[1], GET_MODE (operands[1]),
3730 operands[2], GET_MODE (operands[2]));
3731 if (ret != operands[0])
3732 emit_move_insn (operands[0], ret);
3733
3734 emit_label (div_end_label);
3735 emit_insn (gen_blockage ());
3736 }
3737
3738 /* Implement TARGET_FUNCTION_VALUE. */
3739 static rtx
3740 microblaze_function_value (const_tree valtype,
3741 const_tree func ATTRIBUTE_UNUSED,
3742 bool outgoing ATTRIBUTE_UNUSED)
3743 {
3744 return LIBCALL_VALUE (TYPE_MODE (valtype));
3745 }
3746
3747 /* Implement TARGET_SCHED_ADJUST_COST. */
3748 static int
3749 microblaze_adjust_cost (rtx_insn *, int dep_type, rtx_insn *, int cost,
3750 unsigned int)
3751 {
3752 if (dep_type == REG_DEP_OUTPUT || dep_type == 0)
3753 return cost;
3754 return 0;
3755 }
3756
3757 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3758
3759 At present, GAS doesn't understand li.[sd], so don't allow it
3760 to be generated at present. */
3761 static bool
3762 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
3763 {
3764
3765 if (microblaze_cannot_force_const_mem(mode, x))
3766 return false;
3767
3768 if (GET_CODE (x) == CONST_DOUBLE)
3769 {
3770 return microblaze_const_double_ok (x, GET_MODE (x));
3771 }
3772
3773 /* Handle Case of (const (plus unspec const_int)). */
3774 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
3775 {
3776 rtx p0, p1;
3777
3778 p0 = XEXP (XEXP (x, 0), 0);
3779 p1 = XEXP (XEXP (x, 0), 1);
3780
3781 if (GET_CODE(p1) == CONST_INT)
3782 {
3783 /* Const offset from UNSPEC is not supported. */
3784 if ((GET_CODE (p0) == UNSPEC))
3785 return false;
3786
3787 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3788 && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
3789 return false;
3790 }
3791 }
3792
3793 return true;
3794 }
3795
3796 static rtx
3797 get_branch_target (rtx branch)
3798 {
3799 if (CALL_P (branch))
3800 {
3801 rtx call;
3802
3803 call = XVECEXP (PATTERN (branch), 0, 0);
3804 if (GET_CODE (call) == SET)
3805 call = SET_SRC (call);
3806 if (GET_CODE (call) != CALL)
3807 abort ();
3808 return XEXP (XEXP (call, 0), 0);
3809 }
3810
3811 return NULL_RTX;
3812 }
3813
3814 /* Heuristics to identify where to insert at the
3815 fall through path of the caller function. If there
3816 is a call after the caller branch delay slot then
3817 we dont generate the instruction prefetch instruction.
3818
3819 Scan up to 32 instructions after the call and checks
3820 for the JUMP and call instruction . If there is a call
3821 or JUMP instruction in the range of 32 instruction "wic"
3822 instruction wont be generated. Otherwise insert the "wic"
3823 instruction in the fall through of the call instruction
3824 four instruction after the call. before_4 is used for
3825 the position to insert "wic" instructions. before_16 is
3826 used to check for call and JUMP instruction for first
3827 15 insns. */
3828
3829 static void
3830 insert_wic_for_ilb_runout (rtx_insn *first)
3831 {
3832 rtx_insn *insn;
3833 rtx_insn *before_4 = 0;
3834 rtx_insn *before_16 = 0;
3835 int addr_offset = 0;
3836 int length;
3837 int wic_addr0 = 128 * 4;
3838
3839 int first_addr = INSN_ADDRESSES (INSN_UID (first));
3840
3841 for (insn = first; insn; insn = NEXT_INSN (insn))
3842 if (INSN_P (insn))
3843 {
3844 addr_offset = INSN_ADDRESSES (INSN_UID (insn)) - first_addr;
3845 length = get_attr_length (insn);
3846 if (before_4 == 0 && addr_offset + length >= 4 * 4)
3847 before_4 = insn;
3848
3849 if (JUMP_P(insn))
3850 return;
3851 if (before_16 == 0 && addr_offset + length >= 14 * 4)
3852 before_16 = insn;
3853 if (CALL_P (insn) || tablejump_p (insn, 0, 0))
3854 return;
3855 if (addr_offset + length >= 32 * 4)
3856 {
3857 gcc_assert (before_4 && before_16);
3858 if (wic_addr0 > 4 * 4)
3859 {
3860 insn =
3861 emit_insn_before (gen_iprefetch
3862 (gen_int_mode (addr_offset, SImode)),
3863 before_4);
3864 recog_memoized (insn);
3865 INSN_LOCATION (insn) = INSN_LOCATION (before_4);
3866 INSN_ADDRESSES_NEW (insn, INSN_ADDRESSES (INSN_UID (before_4)));
3867 return;
3868 }
3869 }
3870 }
3871 }
3872
3873 /* Insert instruction prefetch instruction at the fall
3874 through path of the function call. */
3875
3876 static void
3877 insert_wic (void)
3878 {
3879 rtx_insn *insn;
3880 int i;
3881 basic_block bb, prev = 0;
3882 rtx branch_target = 0;
3883
3884 shorten_branches (get_insns ());
3885
3886 for (i = 0; i < n_basic_blocks_for_fn (cfun) - 1; i++)
3887 {
3888 edge e;
3889 edge_iterator ei;
3890 bool simple_loop = false;
3891
3892 bb = BASIC_BLOCK_FOR_FN (cfun, i);
3893
3894 if (bb == NULL)
3895 continue;
3896
3897 if ((prev != 0) && (prev != bb))
3898 continue;
3899 else
3900 prev = 0;
3901
3902 FOR_EACH_EDGE (e, ei, bb->preds)
3903 if (e->src == bb)
3904 {
3905 simple_loop = true;
3906 prev= e->dest;
3907 break;
3908 }
3909
3910 for (insn = BB_END (bb); insn; insn = PREV_INSN (insn))
3911 {
3912 if (INSN_P (insn) && !simple_loop
3913 && CALL_P(insn))
3914 {
3915 if ((branch_target = get_branch_target (insn)))
3916 insert_wic_for_ilb_runout (
3917 next_active_insn (next_active_insn (insn)));
3918 }
3919 if (insn == BB_HEAD (bb))
3920 break;
3921 }
3922 }
3923 }
3924
3925 /* The reorg function defined through the macro
3926 TARGET_MACHINE_DEPENDENT_REORG. */
3927
3928 static void
3929 microblaze_machine_dependent_reorg (void)
3930 {
3931 if (TARGET_PREFETCH)
3932 {
3933 compute_bb_for_insn ();
3934 loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
3935 shorten_branches (get_insns ());
3936 insert_wic ();
3937 loop_optimizer_finalize ();
3938 free_bb_for_insn ();
3939 return;
3940 }
3941 }
3942
3943 /* Implement TARGET_CONSTANT_ALIGNMENT. */
3944
3945 static HOST_WIDE_INT
3946 microblaze_constant_alignment (const_tree exp, HOST_WIDE_INT align)
3947 {
3948 if (TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR)
3949 return MAX (align, BITS_PER_WORD);
3950 return align;
3951 }
3952
3953 /* Implement TARGET_STARTING_FRAME_OFFSET. */
3954
3955 static HOST_WIDE_INT
3956 microblaze_starting_frame_offset (void)
3957 {
3958 return (crtl->outgoing_args_size + FIRST_PARM_OFFSET(FNDECL));
3959 }
3960 \f
3961 #undef TARGET_ENCODE_SECTION_INFO
3962 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3963
3964 #undef TARGET_ASM_GLOBALIZE_LABEL
3965 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3966
3967 #undef TARGET_ASM_FUNCTION_PROLOGUE
3968 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3969
3970 #undef TARGET_ASM_FUNCTION_EPILOGUE
3971 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3972
3973 #undef TARGET_RTX_COSTS
3974 #define TARGET_RTX_COSTS microblaze_rtx_costs
3975
3976 #undef TARGET_CANNOT_FORCE_CONST_MEM
3977 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3978
3979 #undef TARGET_ADDRESS_COST
3980 #define TARGET_ADDRESS_COST microblaze_address_cost
3981
3982 #undef TARGET_ATTRIBUTE_TABLE
3983 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3984
3985 #undef TARGET_IN_SMALL_DATA_P
3986 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3987
3988 #undef TARGET_ASM_SELECT_SECTION
3989 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3990
3991 #undef TARGET_HAVE_SRODATA_SECTION
3992 #define TARGET_HAVE_SRODATA_SECTION true
3993
3994 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3995 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3996 microblaze_function_end_prologue
3997
3998 #undef TARGET_ARG_PARTIAL_BYTES
3999 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
4000
4001 #undef TARGET_FUNCTION_ARG
4002 #define TARGET_FUNCTION_ARG microblaze_function_arg
4003
4004 #undef TARGET_FUNCTION_ARG_ADVANCE
4005 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
4006
4007 #undef TARGET_CAN_ELIMINATE
4008 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
4009
4010 #undef TARGET_LEGITIMIZE_ADDRESS
4011 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
4012
4013 #undef TARGET_LEGITIMATE_ADDRESS_P
4014 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
4015
4016 #undef TARGET_LRA_P
4017 #define TARGET_LRA_P hook_bool_void_false
4018
4019 #undef TARGET_FRAME_POINTER_REQUIRED
4020 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
4021
4022 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
4023 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
4024
4025 #undef TARGET_TRAMPOLINE_INIT
4026 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
4027
4028 #undef TARGET_PROMOTE_FUNCTION_MODE
4029 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
4030
4031 #undef TARGET_FUNCTION_VALUE
4032 #define TARGET_FUNCTION_VALUE microblaze_function_value
4033
4034 #undef TARGET_SECONDARY_RELOAD
4035 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
4036
4037 #undef TARGET_ASM_OUTPUT_MI_THUNK
4038 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
4039
4040 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
4041 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
4042
4043 #undef TARGET_SCHED_ADJUST_COST
4044 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
4045
4046 #undef TARGET_ASM_INIT_SECTIONS
4047 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
4048
4049 #undef TARGET_OPTION_OVERRIDE
4050 #define TARGET_OPTION_OVERRIDE microblaze_option_override
4051
4052 #undef TARGET_LEGITIMATE_CONSTANT_P
4053 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
4054
4055 #undef TARGET_ASM_GENERATE_PIC_ADDR_DIFF_VEC
4056 #define TARGET_ASM_GENERATE_PIC_ADDR_DIFF_VEC microblaze_gen_pic_addr_dif_vec
4057
4058 #undef TARGET_MACHINE_DEPENDENT_REORG
4059 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg
4060
4061 #undef TARGET_HARD_REGNO_MODE_OK
4062 #define TARGET_HARD_REGNO_MODE_OK microblaze_hard_regno_mode_ok
4063
4064 #undef TARGET_MODES_TIEABLE_P
4065 #define TARGET_MODES_TIEABLE_P microblaze_modes_tieable_p
4066
4067 #undef TARGET_CONSTANT_ALIGNMENT
4068 #define TARGET_CONSTANT_ALIGNMENT microblaze_constant_alignment
4069
4070 #undef TARGET_STARTING_FRAME_OFFSET
4071 #define TARGET_STARTING_FRAME_OFFSET microblaze_starting_frame_offset
4072
4073 struct gcc_target targetm = TARGET_INITIALIZER;
4074 \f
4075 #include "gt-microblaze.h"