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