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