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