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