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