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