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