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