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