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