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