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