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