comparison gcc/config/microblaze/microblaze.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents 561a7518be6b
children 84e7813d76e9
comparison
equal deleted inserted replaced
68:561a7518be6b 111:04ced10e8804
1 /* Subroutines used for code generation on Xilinx MicroBlaze. 1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright 2009, 2010 Free Software Foundation, Inc. 2 Copyright (C) 2009-2017 Free Software Foundation, Inc.
3 3
4 Contributed by Michael Eager <eager@eagercon.com>. 4 Contributed by Michael Eager <eager@eagercon.com>.
5 5
6 This file is part of GCC. 6 This file is part of GCC.
7 7
20 <http://www.gnu.org/licenses/>. */ 20 <http://www.gnu.org/licenses/>. */
21 21
22 #include "config.h" 22 #include "config.h"
23 #include "system.h" 23 #include "system.h"
24 #include "coretypes.h" 24 #include "coretypes.h"
25 #include "tm.h" 25 #include "backend.h"
26 #include "target.h"
26 #include "rtl.h" 27 #include "rtl.h"
28 #include "tree.h"
29 #include "stringpool.h"
30 #include "attribs.h"
31 #include "df.h"
32 #include "memmodel.h"
33 #include "tm_p.h"
34 #include "optabs.h"
27 #include "regs.h" 35 #include "regs.h"
28 #include "hard-reg-set.h" 36 #include "emit-rtl.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" 37 #include "recog.h"
36 #include "tree.h" 38 #include "cgraph.h"
37 #include "function.h" 39 #include "diagnostic-core.h"
40 #include "varasm.h"
41 #include "stor-layout.h"
42 #include "calls.h"
43 #include "explow.h"
38 #include "expr.h" 44 #include "expr.h"
39 #include "flags.h"
40 #include "reload.h" 45 #include "reload.h"
41 #include "output.h" 46 #include "output.h"
42 #include "ggc.h" 47 #include "builtins.h"
43 #include "hashtab.h" 48 #include "rtl-iter.h"
44 #include "target.h" 49 #include "cfgloop.h"
50 #include "insn-addr.h"
51 #include "cfgrtl.h"
52
53 /* This file should be included last. */
45 #include "target-def.h" 54 #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 55
52 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB) 56 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
53 57
54 /* Classifies an address. 58 /* Classifies an address.
55 59
82 ADDRESS_REG, 86 ADDRESS_REG,
83 ADDRESS_REG_INDEX, 87 ADDRESS_REG_INDEX,
84 ADDRESS_CONST_INT, 88 ADDRESS_CONST_INT,
85 ADDRESS_SYMBOLIC, 89 ADDRESS_SYMBOLIC,
86 ADDRESS_GOTOFF, 90 ADDRESS_GOTOFF,
87 ADDRESS_PLT 91 ADDRESS_PLT,
92 ADDRESS_TLS
88 }; 93 };
89 94
90 /* Classifies symbols 95 /* Classifies symbols
91 96
92 SYMBOL_TYPE_GENERAL 97 SYMBOL_TYPE_GENERAL
94 A general symbol. */ 99 A general symbol. */
95 enum microblaze_symbol_type 100 enum microblaze_symbol_type
96 { 101 {
97 SYMBOL_TYPE_INVALID, 102 SYMBOL_TYPE_INVALID,
98 SYMBOL_TYPE_GENERAL 103 SYMBOL_TYPE_GENERAL
104 };
105
106 /* TLS Address Type. */
107 enum tls_reloc {
108 TLS_GD,
109 TLS_LDM,
110 TLS_DTPREL,
111 TLS_IE,
112 TLS_LE
99 }; 113 };
100 114
101 /* Classification of a MicroBlaze address. */ 115 /* Classification of a MicroBlaze address. */
102 struct microblaze_address_info 116 struct microblaze_address_info
103 { 117 {
106 ADDRESS_SYMBOLIC. */ 120 ADDRESS_SYMBOLIC. */
107 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */ 121 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
108 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */ 122 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
109 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */ 123 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
110 enum microblaze_symbol_type symbol_type; 124 enum microblaze_symbol_type symbol_type;
125 enum tls_reloc tls_type;
111 }; 126 };
112 127
113 /* Structure to be filled in by compute_frame_size with register 128 /* Structure to be filled in by compute_frame_size with register
114 save masks, and offsets for the current function. */ 129 save masks, and offsets for the current function. */
115 130
141 156
142 /* Prevent scheduling potentially exception causing instructions in 157 /* Prevent scheduling potentially exception causing instructions in
143 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */ 158 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
144 int microblaze_no_unsafe_delay; 159 int microblaze_no_unsafe_delay;
145 160
161 /* Set to one if the targeted core has the CLZ insn. */
162 int microblaze_has_clz = 0;
163
146 /* Which CPU pipeline do we use. We haven't really standardized on a CPU 164 /* 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 165 version having only a particular type of pipeline. There can still be
148 options on the CPU to scale pipeline features up or down. :( 166 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 167 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 168 this variable instead Making PIPE_5 the default. It should be backward
151 optimal with PIPE_3 MicroBlazes. */ 169 optimal with PIPE_3 MicroBlazes. */
152 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5; 170 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
153 171
154 /* High and low marks for floating point values which we will accept 172 /* High and low marks for floating point values which we will accept
155 as legitimate constants for LEGITIMATE_CONSTANT_P. These are 173 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
156 initialized in override_options. */ 174 initialized in override_options. */
157 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow; 175 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
158 176
159 /* Array giving truth value on whether or not a given hard register 177 /* Array giving truth value on whether or not a given hard register
160 can support a given mode. */ 178 can support a given mode. */
161 char microblaze_hard_regno_mode_ok[(int)MAX_MACHINE_MODE] 179 static char microblaze_hard_regno_mode_ok_p[(int)MAX_MACHINE_MODE]
162 [FIRST_PSEUDO_REGISTER]; 180 [FIRST_PSEUDO_REGISTER];
163 181
164 /* Current frame information calculated by compute_frame_size. */ 182 /* Current frame information calculated by compute_frame_size. */
165 struct microblaze_frame_info current_frame_info; 183 struct microblaze_frame_info current_frame_info;
166 184
167 /* Zero structure to initialize current_frame_info. */ 185 /* Zero structure to initialize current_frame_info. */
188 }; 206 };
189 207
190 /* MicroBlaze specific machine attributes. 208 /* MicroBlaze specific machine attributes.
191 interrupt_handler - Interrupt handler attribute to add interrupt prologue 209 interrupt_handler - Interrupt handler attribute to add interrupt prologue
192 and epilogue and use appropriate interrupt return. 210 and epilogue and use appropriate interrupt return.
193 save_volatiles - Similiar to interrupt handler, but use normal return. */ 211 save_volatiles - Similar to interrupt handler, but use normal return. */
194 int interrupt_handler; 212 int interrupt_handler;
213 int break_handler;
214 int fast_interrupt;
195 int save_volatiles; 215 int save_volatiles;
196 216
197 const struct attribute_spec microblaze_attribute_table[] = { 217 const struct attribute_spec microblaze_attribute_table[] = {
198 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler */ 218 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
199 {"interrupt_handler", 0, 0, true, false, false, NULL}, 219 affects_type_identity */
200 {"save_volatiles" , 0, 0, true, false, false, NULL}, 220 {"interrupt_handler", 0, 0, true, false, false, NULL,
201 { NULL, 0, 0, false, false, false, NULL} 221 false },
222 {"break_handler", 0, 0, true, false, false, NULL,
223 false },
224 {"fast_interrupt", 0, 0, true, false, false, NULL,
225 false },
226 {"save_volatiles" , 0, 0, true, false, false, NULL,
227 false },
228 { NULL, 0, 0, false, false, false, NULL,
229 false }
202 }; 230 };
203 231
204 static int microblaze_interrupt_function_p (tree); 232 static int microblaze_interrupt_function_p (tree);
205 233
234 static void microblaze_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
235 static void microblaze_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
236
206 section *sdata2_section; 237 section *sdata2_section;
207 238
239 #ifdef HAVE_AS_TLS
240 #undef TARGET_HAVE_TLS
241 #define TARGET_HAVE_TLS true
242 #endif
243
208 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */ 244 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
209 int 245 static bool
210 microblaze_const_double_ok (rtx op, enum machine_mode mode) 246 microblaze_const_double_ok (rtx op, machine_mode mode)
211 { 247 {
212 REAL_VALUE_TYPE d; 248 REAL_VALUE_TYPE d;
213 249
214 if (GET_CODE (op) != CONST_DOUBLE) 250 if (GET_CODE (op) != CONST_DOUBLE)
215 return 0; 251 return 0;
216 252
217 if (mode == VOIDmode) 253 if (GET_MODE (op) == VOIDmode)
218 return 1; 254 return 1;
219 255
220 if (mode != SFmode && mode != DFmode) 256 if (mode != SFmode && mode != DFmode)
221 return 0; 257 return 0;
222 258
223 if (op == CONST0_RTX (mode)) 259 if (op == CONST0_RTX (mode))
224 return 1; 260 return 1;
225 261
226 REAL_VALUE_FROM_CONST_DOUBLE (d, op); 262 d = *CONST_DOUBLE_REAL_VALUE (op);
227 263
228 if (REAL_VALUE_ISNAN (d)) 264 if (REAL_VALUE_ISNAN (d))
229 return FALSE; 265 return FALSE;
230 266
231 if (REAL_VALUE_NEGATIVE (d)) 267 if (REAL_VALUE_NEGATIVE (d))
232 d = real_value_negate (&d); 268 d = real_value_negate (&d);
233 269
234 if (mode == DFmode) 270 if (mode == DFmode)
235 { 271 {
236 if (REAL_VALUES_LESS (d, dfhigh) && REAL_VALUES_LESS (dflow, d)) 272 if (real_less (&d, &dfhigh) && real_less (&dflow, &d))
237 return 1; 273 return 1;
238 } 274 }
239 else 275 else
240 { 276 {
241 if (REAL_VALUES_LESS (d, sfhigh) && REAL_VALUES_LESS (sflow, d)) 277 if (real_less (&d, &sfhigh) && real_less (&sflow, &d))
242 return 1; 278 return 1;
243 } 279 }
244 280
245 return 0; 281 return 0;
246 } 282 }
247 283
248 /* Return truth value if a memory operand fits in a single instruction 284 /* Return truth value if a memory operand fits in a single instruction
249 (ie, register + small offset) or (register + register). */ 285 (ie, register + small offset) or (register + register). */
250 286
251 int 287 int
252 simple_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) 288 simple_memory_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
253 { 289 {
254 rtx addr, plus0, plus1; 290 rtx addr, plus0, plus1;
255 291
256 /* Eliminate non-memory operations. */ 292 /* Eliminate non-memory operations. */
257 if (GET_CODE (op) != MEM) 293 if (GET_CODE (op) != MEM)
274 return 1; 310 return 1;
275 311
276 case PLUS: 312 case PLUS:
277 plus0 = XEXP (addr, 0); 313 plus0 = XEXP (addr, 0);
278 plus1 = XEXP (addr, 1); 314 plus1 = XEXP (addr, 1);
315
316 if (GET_CODE (plus0) != REG)
317 return 0;
279 318
280 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT 319 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
281 && SMALL_INT (plus1)) 320 && SMALL_INT (plus1))
282 { 321 {
283 return 1; 322 return 1;
305 344
306 /* Return nonzero for a memory address that can be used to load or store 345 /* Return nonzero for a memory address that can be used to load or store
307 a doubleword. */ 346 a doubleword. */
308 347
309 int 348 int
310 double_memory_operand (rtx op, enum machine_mode mode) 349 double_memory_operand (rtx op, machine_mode mode)
311 { 350 {
312 rtx addr; 351 rtx addr;
313 352
314 if (GET_CODE (op) != MEM || !memory_operand (op, mode)) 353 if (GET_CODE (op) != MEM || !memory_operand (op, mode))
315 { 354 {
320 memory. */ 359 memory. */
321 if (reload_in_progress 360 if (reload_in_progress
322 && GET_CODE (op) == REG 361 && GET_CODE (op) == REG
323 && REGNO (op) >= FIRST_PSEUDO_REGISTER 362 && REGNO (op) >= FIRST_PSEUDO_REGISTER
324 && reg_renumber[REGNO (op)] < 0 363 && reg_renumber[REGNO (op)] < 0
325 && reg_equiv_mem[REGNO (op)] != 0 364 && reg_equiv_mem (REGNO (op)) != 0
326 && double_memory_operand (reg_equiv_mem[REGNO (op)], mode)) 365 && double_memory_operand (reg_equiv_mem (REGNO (op)), mode))
327 return 1; 366 return 1;
328 return 0; 367 return 0;
329 } 368 }
330 369
331 /* Make sure that 4 added to the address is a valid memory address. 370 /* Make sure that 4 added to the address is a valid memory address.
335 374
336 if (CONSTANT_ADDRESS_P (addr)) 375 if (CONSTANT_ADDRESS_P (addr))
337 return 1; 376 return 1;
338 377
339 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT 378 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
340 ? SImode : SFmode), plus_constant (addr, 4)); 379 ? E_SImode : E_SFmode),
380 plus_constant (Pmode, addr, 4));
341 } 381 }
342 382
343 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */ 383 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
344 int 384 int
345 microblaze_regno_ok_for_base_p (int regno, int strict) 385 microblaze_regno_ok_for_base_p (int regno, int strict)
363 /* Return true if X is a valid base register for the given mode. 403 /* Return true if X is a valid base register for the given mode.
364 Allow only hard registers if STRICT. */ 404 Allow only hard registers if STRICT. */
365 405
366 static bool 406 static bool
367 microblaze_valid_base_register_p (rtx x, 407 microblaze_valid_base_register_p (rtx x,
368 enum machine_mode mode ATTRIBUTE_UNUSED, 408 machine_mode mode ATTRIBUTE_UNUSED,
369 int strict) 409 int strict)
370 { 410 {
371 if (!strict && GET_CODE (x) == SUBREG) 411 if (!strict && GET_CODE (x) == SUBREG)
372 x = SUBREG_REG (x); 412 x = SUBREG_REG (x);
373 413
374 return (GET_CODE (x) == REG 414 return (GET_CODE (x) == REG
375 && microblaze_regno_ok_for_base_p (REGNO (x), strict)); 415 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
376 } 416 }
377 417
418 /* Build the SYMBOL_REF for __tls_get_addr. */
419
420 static GTY(()) rtx tls_get_addr_libfunc;
421
422 static rtx
423 get_tls_get_addr (void)
424 {
425 if (!tls_get_addr_libfunc)
426 tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
427 return tls_get_addr_libfunc;
428 }
429
430 /* Return TRUE if X is a thread-local symbol. */
431 bool
432 microblaze_tls_symbol_p (rtx x)
433 {
434 if (!TARGET_HAVE_TLS)
435 return false;
436
437 if (GET_CODE (x) != SYMBOL_REF)
438 return false;
439
440 return SYMBOL_REF_TLS_MODEL (x) != 0;
441 }
442
443 /* Return TRUE if X contains any TLS symbol references. */
444
445 bool
446 microblaze_tls_referenced_p (rtx x)
447 {
448 if (!TARGET_HAVE_TLS)
449 return false;
450 subrtx_iterator::array_type array;
451 FOR_EACH_SUBRTX (iter, array, x, ALL)
452 {
453 const_rtx x = *iter;
454 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0)
455 return true;
456 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
457 TLS offsets, not real symbol references. */
458 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
459 iter.skip_subrtxes ();
460 }
461 return false;
462 }
463
464 bool
465 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
466 {
467 return microblaze_tls_referenced_p(x);
468 }
469
470 /* Return TRUE if X references a SYMBOL_REF. */
471 int
472 symbol_mentioned_p (rtx x)
473 {
474 const char * fmt;
475 int i;
476
477 if (GET_CODE (x) == SYMBOL_REF)
478 return 1;
479
480 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
481 are constant offsets, not symbols. */
482 if (GET_CODE (x) == UNSPEC)
483 return 0;
484
485 fmt = GET_RTX_FORMAT (GET_CODE (x));
486
487 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
488 {
489 if (fmt[i] == 'E')
490 {
491 int j;
492
493 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
494 if (symbol_mentioned_p (XVECEXP (x, i, j)))
495 return 1;
496 }
497 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
498 return 1;
499 }
500
501 return 0;
502 }
503
504 /* Return TRUE if X references a LABEL_REF. */
505 int
506 label_mentioned_p (rtx x)
507 {
508 const char * fmt;
509 int i;
510
511 if (GET_CODE (x) == LABEL_REF)
512 return 1;
513
514 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
515 instruction, but they are constant offsets, not symbols. */
516 if (GET_CODE (x) == UNSPEC)
517 return 0;
518
519 fmt = GET_RTX_FORMAT (GET_CODE (x));
520 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
521 {
522 if (fmt[i] == 'E')
523 {
524 int j;
525
526 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
527 if (label_mentioned_p (XVECEXP (x, i, j)))
528 return 1;
529 }
530 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
531 return 1;
532 }
533
534 return 0;
535 }
536
537 int
538 tls_mentioned_p (rtx x)
539 {
540 switch (GET_CODE (x))
541 {
542 case CONST:
543 return tls_mentioned_p (XEXP (x, 0));
544
545 case UNSPEC:
546 if (XINT (x, 1) == UNSPEC_TLS)
547 return 1;
548 return 0;
549
550 default:
551 return 0;
552 }
553 }
554
555 static rtx
556 load_tls_operand (rtx x, rtx reg)
557 {
558 rtx tmp;
559
560 if (reg == NULL_RTX)
561 reg = gen_reg_rtx (Pmode);
562
563 tmp = gen_rtx_CONST (Pmode, x);
564
565 emit_insn (gen_rtx_SET (reg,
566 gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
567
568 return reg;
569 }
570
571 static rtx_insn *
572 microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
573 {
574 rtx_insn *insns;
575 rtx tls_entry;
576
577 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
578
579 start_sequence ();
580
581 tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
582 UNSPEC_TLS);
583
584 reg = load_tls_operand (tls_entry, reg);
585
586 *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
587 LCT_PURE, /* LCT_CONST? */
588 Pmode, reg, Pmode);
589
590 insns = get_insns ();
591 end_sequence ();
592
593 return insns;
594 }
595
596 rtx
597 microblaze_legitimize_tls_address(rtx x, rtx reg)
598 {
599 rtx dest, ret, eqv, addend;
600 rtx_insn *insns;
601 enum tls_model model;
602 model = SYMBOL_REF_TLS_MODEL (x);
603
604 switch (model)
605 {
606 case TLS_MODEL_LOCAL_DYNAMIC:
607 case TLS_MODEL_GLOBAL_DYNAMIC:
608 case TLS_MODEL_INITIAL_EXEC:
609 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
610 dest = gen_reg_rtx (Pmode);
611 emit_libcall_block (insns, dest, ret, x);
612 break;
613
614 case TLS_MODEL_LOCAL_EXEC:
615 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
616
617 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
618 share the LDM result with other LD model accesses. */
619 eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
620 dest = gen_reg_rtx (Pmode);
621 emit_libcall_block (insns, dest, ret, eqv);
622
623 /* Load the addend. */
624 addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
625 UNSPEC_TLS);
626 addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
627 dest = gen_rtx_PLUS (Pmode, dest, addend);
628 break;
629
630 default:
631 gcc_unreachable ();
632 }
633 return dest;
634 }
635
378 static bool 636 static bool
379 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x) 637 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
380 { 638 {
381 info->symbol_type = SYMBOL_TYPE_GENERAL; 639 info->symbol_type = SYMBOL_TYPE_GENERAL;
382 info->symbol = XVECEXP (x, 0, 0); 640 info->symbol = XVECEXP (x, 0, 0);
388 } 646 }
389 else if (XINT (x, 1) == UNSPEC_PLT) 647 else if (XINT (x, 1) == UNSPEC_PLT)
390 { 648 {
391 info->type = ADDRESS_PLT; 649 info->type = ADDRESS_PLT;
392 } 650 }
651 else if (XINT (x, 1) == UNSPEC_TLS)
652 {
653 info->type = ADDRESS_TLS;
654 info->tls_type = tls_reloc (INTVAL (XVECEXP (x, 0, 1)));
655 }
393 else 656 else
394 { 657 {
395 return false; 658 return false;
396 } 659 }
397 return true; 660 return true;
401 /* Return true if X is a valid index register for the given mode. 664 /* Return true if X is a valid index register for the given mode.
402 Allow only hard registers if STRICT. */ 665 Allow only hard registers if STRICT. */
403 666
404 static bool 667 static bool
405 microblaze_valid_index_register_p (rtx x, 668 microblaze_valid_index_register_p (rtx x,
406 enum machine_mode mode ATTRIBUTE_UNUSED, 669 machine_mode mode ATTRIBUTE_UNUSED,
407 int strict) 670 int strict)
408 { 671 {
409 if (!strict && GET_CODE (x) == SUBREG) 672 if (!strict && GET_CODE (x) == SUBREG)
410 x = SUBREG_REG (x); 673 x = SUBREG_REG (x);
411 674
418 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */ 681 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
419 static int 682 static int
420 get_base_reg (rtx x) 683 get_base_reg (rtx x)
421 { 684 {
422 tree decl; 685 tree decl;
423 int base_reg = (flag_pic ? MB_ABI_PIC_ADDR_REGNUM : MB_ABI_BASE_REGNUM); 686 int base_reg;
687
688 if (!flag_pic || microblaze_tls_symbol_p(x))
689 base_reg = MB_ABI_BASE_REGNUM;
690 else if (flag_pic)
691 base_reg = MB_ABI_PIC_ADDR_REGNUM;
424 692
425 if (TARGET_XLGPOPT 693 if (TARGET_XLGPOPT
426 && GET_CODE (x) == SYMBOL_REF 694 && GET_CODE (x) == SYMBOL_REF
427 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL) 695 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
428 { 696 {
457 adjacent memory cells are accessed by adding word-sized offsets 725 adjacent memory cells are accessed by adding word-sized offsets
458 during assembly output. */ 726 during assembly output. */
459 727
460 static bool 728 static bool
461 microblaze_classify_address (struct microblaze_address_info *info, rtx x, 729 microblaze_classify_address (struct microblaze_address_info *info, rtx x,
462 enum machine_mode mode, int strict) 730 machine_mode mode, int strict)
463 { 731 {
464 rtx xplus0; 732 rtx xplus0;
465 rtx xplus1; 733 rtx xplus1;
466 734
467 info->type = ADDRESS_INVALID; 735 info->type = ADDRESS_INVALID;
496 info->offset = xplus1; 764 info->offset = xplus1;
497 return true; 765 return true;
498 } 766 }
499 else if (GET_CODE (xplus1) == UNSPEC) 767 else if (GET_CODE (xplus1) == UNSPEC)
500 { 768 {
769 /* Need offsettable address. */
770 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
771 return false;
772
501 return microblaze_classify_unspec (info, xplus1); 773 return microblaze_classify_unspec (info, xplus1);
502 } 774 }
503 else if ((GET_CODE (xplus1) == SYMBOL_REF || 775 else if ((GET_CODE (xplus1) == SYMBOL_REF ||
504 GET_CODE (xplus1) == LABEL_REF) && flag_pic == 2) 776 GET_CODE (xplus1) == LABEL_REF))
505 { 777 {
506 return false; 778 if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
507 } 779 return false;
508 else if (GET_CODE (xplus1) == SYMBOL_REF ||
509 GET_CODE (xplus1) == LABEL_REF ||
510 GET_CODE (xplus1) == CONST)
511 {
512 if (GET_CODE (XEXP (xplus1, 0)) == UNSPEC)
513 return microblaze_classify_unspec (info, XEXP (xplus1, 0));
514 else if (flag_pic == 2)
515 {
516 return false;
517 }
518 info->type = ADDRESS_SYMBOLIC; 780 info->type = ADDRESS_SYMBOLIC;
519 info->symbol = xplus1; 781 info->symbol = xplus1;
520 info->symbol_type = SYMBOL_TYPE_GENERAL; 782 info->symbol_type = SYMBOL_TYPE_GENERAL;
521 return true; 783 return true;
784 }
785 else if (GET_CODE (xplus1) == CONST)
786 {
787 rtx xconst0 = XEXP(xplus1, 0);
788
789 /* base + unspec. */
790 if (GET_CODE (xconst0) == UNSPEC)
791 {
792 /* Need offsettable address. */
793 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
794 return false;
795 return microblaze_classify_unspec(info, xconst0);
796 }
797
798 /* for (plus x const_int) just look at x. */
799 if (GET_CODE (xconst0) == PLUS
800 && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
801 && SMALL_INT (XEXP (xconst0, 1)))
802 {
803 /* This is ok as info->symbol is set to xplus1 the full
804 const-expression below. */
805 xconst0 = XEXP (xconst0, 0);
806 }
807
808 if (GET_CODE (xconst0) == SYMBOL_REF
809 || GET_CODE (xconst0) == LABEL_REF)
810 {
811 if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
812 return false;
813
814 info->type = ADDRESS_SYMBOLIC;
815 info->symbol = xplus1;
816 info->symbol_type = SYMBOL_TYPE_GENERAL;
817 return true;
818 }
819
820 /* Not base + symbol || base + UNSPEC. */
821 return false;
822
522 } 823 }
523 else if (GET_CODE (xplus1) == REG 824 else if (GET_CODE (xplus1) == REG
524 && microblaze_valid_index_register_p (xplus1, mode, 825 && microblaze_valid_index_register_p (xplus1, mode,
525 strict) 826 strict)
526 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)) 827 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
533 } 834 }
534 break; 835 break;
535 } 836 }
536 case CONST_INT: 837 case CONST_INT:
537 { 838 {
538 info->regA = gen_rtx_raw_REG (mode, 0); 839 info->regA = gen_raw_REG (mode, 0);
539 info->type = ADDRESS_CONST_INT; 840 info->type = ADDRESS_CONST_INT;
540 info->offset = x; 841 info->offset = x;
541 return true; 842 return true;
542 } 843 }
543 case CONST: 844 case CONST:
545 case SYMBOL_REF: 846 case SYMBOL_REF:
546 { 847 {
547 info->type = ADDRESS_SYMBOLIC; 848 info->type = ADDRESS_SYMBOLIC;
548 info->symbol_type = SYMBOL_TYPE_GENERAL; 849 info->symbol_type = SYMBOL_TYPE_GENERAL;
549 info->symbol = x; 850 info->symbol = x;
550 info->regA = gen_rtx_raw_REG (mode, get_base_reg (x)); 851 info->regA = gen_raw_REG (mode, get_base_reg (x));
551 852
552 if (GET_CODE (x) == CONST) 853 if (GET_CODE (x) == CONST)
553 { 854 {
554 return !(flag_pic && pic_address_needs_scratch (x)); 855 if (GET_CODE (XEXP (x, 0)) == UNSPEC)
856 {
857 info->regA = gen_raw_REG (mode,
858 get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
859 return microblaze_classify_unspec (info, XEXP (x, 0));
860 }
861 return !(flag_pic && pic_address_needs_scratch (x));
555 } 862 }
556 else if (flag_pic == 2) 863
557 { 864 if (flag_pic == 2)
558 return false; 865 return false;
559 } 866 else if (microblaze_tls_symbol_p(x))
867 return false;
560 868
561 return true; 869 return true;
562 } 870 }
563 871
564 case UNSPEC: 872 case UNSPEC:
579 returns a nonzero value if X is a legitimate address for a memory 887 returns a nonzero value if X is a legitimate address for a memory
580 operand of the indicated MODE. STRICT is nonzero if this function 888 operand of the indicated MODE. STRICT is nonzero if this function
581 is called during reload. */ 889 is called during reload. */
582 890
583 bool 891 bool
584 microblaze_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) 892 microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict)
585 { 893 {
586 struct microblaze_address_info addr; 894 struct microblaze_address_info addr;
587 895
588 return microblaze_classify_address (&addr, x, mode, strict); 896 return microblaze_classify_address (&addr, x, mode, strict);
589 } 897 }
590 898
899 int
900 microblaze_valid_pic_const (rtx x)
901 {
902 switch (GET_CODE (x))
903 {
904 case CONST:
905 case CONST_INT:
906 case CONST_DOUBLE:
907 return true;
908 default:
909 return false;
910 }
911 }
912
913 int
914 microblaze_legitimate_pic_operand (rtx x)
915 {
916 if (flag_pic == 2 && (symbol_mentioned_p(x) || label_mentioned_p(x)))
917 return 0;
918
919 if (microblaze_tls_referenced_p(x))
920 return 0;
921
922 return 1;
923 }
591 924
592 /* Try machine-dependent ways of modifying an illegitimate address 925 /* Try machine-dependent ways of modifying an illegitimate address
593 to be legitimate. If we find one, return the new, valid address. 926 to be legitimate. If we find one, return the new, valid address.
594 This is used from only one place: `memory_address' in explow.c. 927 This is used from only one place: `memory_address' in explow.c.
595 928
615 When PIC, convert addresses of the form memory (symbol+large int) to 948 When PIC, convert addresses of the form memory (symbol+large int) to
616 memory (reg+large int). */ 949 memory (reg+large int). */
617 950
618 static rtx 951 static rtx
619 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, 952 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
620 enum machine_mode mode ATTRIBUTE_UNUSED) 953 machine_mode mode ATTRIBUTE_UNUSED)
621 { 954 {
622 register rtx xinsn = x, result; 955 register rtx xinsn = x, result;
623 956
624 if (GET_CODE (xinsn) == CONST 957 if (GET_CODE (xinsn) == CONST
625 && flag_pic && pic_address_needs_scratch (xinsn)) 958 && flag_pic && pic_address_needs_scratch (xinsn))
658 rtx int_reg = gen_reg_rtx (Pmode); 991 rtx int_reg = gen_reg_rtx (Pmode);
659 rtx ptr_reg = gen_reg_rtx (Pmode); 992 rtx ptr_reg = gen_reg_rtx (Pmode);
660 993
661 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff)); 994 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
662 995
663 emit_insn (gen_rtx_SET (VOIDmode, 996 emit_insn (gen_rtx_SET (ptr_reg,
664 ptr_reg,
665 gen_rtx_PLUS (Pmode, xplus0, int_reg))); 997 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
666 998
667 result = gen_rtx_PLUS (Pmode, ptr_reg, 999 result = gen_rtx_PLUS (Pmode, ptr_reg,
668 GEN_INT (INTVAL (xplus1) & 0x7fff)); 1000 GEN_INT (INTVAL (xplus1) & 0x7fff));
669 return result; 1001 return result;
670 } 1002 }
671 1003
672 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0) && flag_pic == 2) 1004 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
673 { 1005 {
674 if (reload_in_progress) 1006 if (reload_in_progress)
675 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); 1007 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
676 if (code1 == CONST) 1008 if (code1 == CONST)
677 { 1009 {
678 xplus1 = XEXP (xplus1, 0); 1010 xplus1 = XEXP (xplus1, 0);
679 code1 = GET_CODE (xplus1); 1011 code1 = GET_CODE (xplus1);
680 } 1012 }
681 if (code1 == SYMBOL_REF) 1013 if (code1 == SYMBOL_REF)
682 { 1014 {
683 result = 1015 if (microblaze_tls_symbol_p(xplus1))
684 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1), UNSPEC_GOTOFF); 1016 {
685 result = gen_rtx_CONST (Pmode, result); 1017 rtx tls_ref, reg;
686 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result); 1018 reg = gen_reg_rtx (Pmode);
687 result = gen_const_mem (Pmode, result); 1019
688 result = gen_rtx_PLUS (Pmode, xplus0, result); 1020 tls_ref = microblaze_legitimize_tls_address (xplus1,
689 return result; 1021 NULL_RTX);
1022 emit_move_insn (reg, tls_ref);
1023
1024 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1025
1026 return result;
1027 }
1028 else if (flag_pic == 2)
1029 {
1030 rtx pic_ref, reg;
1031 reg = gen_reg_rtx (Pmode);
1032
1033 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1),
1034 UNSPEC_GOTOFF);
1035 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1036 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1037 pic_ref = gen_const_mem (Pmode, pic_ref);
1038 emit_move_insn (reg, pic_ref);
1039 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1040 return result;
1041 }
690 } 1042 }
691 } 1043 }
692 } 1044 }
693 1045
694 if (GET_CODE (xinsn) == SYMBOL_REF) 1046 if (GET_CODE (xinsn) == SYMBOL_REF)
695 { 1047 {
696 if (reload_in_progress) 1048 rtx reg;
697 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); 1049 if (microblaze_tls_symbol_p(xinsn))
698 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF); 1050 {
699 result = gen_rtx_CONST (Pmode, result); 1051 reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
700 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result); 1052 }
701 result = gen_const_mem (Pmode, result); 1053 else
702 return result; 1054 {
1055 rtx pic_ref;
1056
1057 if (reload_in_progress)
1058 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1059
1060 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
1061 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1062 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1063 pic_ref = gen_const_mem (Pmode, pic_ref);
1064 reg = pic_ref;
1065 }
1066 return reg;
703 } 1067 }
704 1068
705 return x; 1069 return x;
706 } 1070 }
707 1071
717 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length) 1081 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
718 { 1082 {
719 HOST_WIDE_INT offset, delta; 1083 HOST_WIDE_INT offset, delta;
720 unsigned HOST_WIDE_INT bits; 1084 unsigned HOST_WIDE_INT bits;
721 int i; 1085 int i;
722 enum machine_mode mode; 1086 machine_mode mode;
723 rtx *regs; 1087 rtx *regs;
724 1088
725 bits = BITS_PER_WORD; 1089 bits = BITS_PER_WORD;
726 mode = mode_for_size (bits, MODE_INT, 0); 1090 mode = int_mode_for_size (bits, 0).require ();
727 delta = bits / BITS_PER_UNIT; 1091 delta = bits / BITS_PER_UNIT;
728 1092
729 /* Allocate a buffer for the temporary registers. */ 1093 /* Allocate a buffer for the temporary registers. */
730 regs = XALLOCAVEC (rtx, length / delta); 1094 regs = XALLOCAVEC (rtx, length / delta);
731 1095
779 memory regions do not overlap. */ 1143 memory regions do not overlap. */
780 1144
781 static void 1145 static void
782 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length) 1146 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
783 { 1147 {
784 rtx label, src_reg, dest_reg, final_src; 1148 rtx_code_label *label;
1149 rtx src_reg, dest_reg, final_src;
785 HOST_WIDE_INT leftover; 1150 HOST_WIDE_INT leftover;
786 1151
787 leftover = length % MAX_MOVE_BYTES; 1152 leftover = length % MAX_MOVE_BYTES;
788 length -= leftover; 1153 length -= leftover;
789 1154
802 1167
803 /* Emit the loop body. */ 1168 /* Emit the loop body. */
804 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES); 1169 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
805 1170
806 /* Move on to the next block. */ 1171 /* Move on to the next block. */
807 emit_move_insn (src_reg, plus_constant (src_reg, MAX_MOVE_BYTES)); 1172 emit_move_insn (src_reg, plus_constant (Pmode, src_reg, MAX_MOVE_BYTES));
808 emit_move_insn (dest_reg, plus_constant (dest_reg, MAX_MOVE_BYTES)); 1173 emit_move_insn (dest_reg, plus_constant (Pmode, dest_reg, MAX_MOVE_BYTES));
809 1174
810 /* Emit the test & branch. */ 1175 /* Emit the test & branch. */
811 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src), 1176 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
812 src_reg, final_src, label)); 1177 src_reg, final_src, label));
813 1178
855 } 1220 }
856 return false; 1221 return false;
857 } 1222 }
858 1223
859 static bool 1224 static bool
860 microblaze_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total, 1225 microblaze_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
1226 int opno ATTRIBUTE_UNUSED, int *total,
861 bool speed ATTRIBUTE_UNUSED) 1227 bool speed ATTRIBUTE_UNUSED)
862 { 1228 {
863 enum machine_mode mode = GET_MODE (x); 1229 int code = GET_CODE (x);
864 1230
865 switch (code) 1231 switch (code)
866 { 1232 {
867 case MEM: 1233 case MEM:
868 { 1234 {
913 *total = COSTS_N_INSNS (1); 1279 *total = COSTS_N_INSNS (1);
914 else if (GET_CODE (XEXP (x, 1)) == CONST_INT) 1280 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
915 { 1281 {
916 /* Add 1 to make shift slightly more expensive than add. */ 1282 /* Add 1 to make shift slightly more expensive than add. */
917 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1; 1283 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
918 /* Reduce shift costs for for special circumstances. */ 1284 /* Reduce shift costs for special circumstances. */
919 if (optimize_size && INTVAL (XEXP (x, 1)) > 5) 1285 if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
920 *total -= 2; 1286 *total -= 2;
921 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17) 1287 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
922 *total -= 2; 1288 *total -= 2;
923 } 1289 }
1002 1368
1003 /* Return the number of instructions needed to load or store a value 1369 /* Return the number of instructions needed to load or store a value
1004 of mode MODE at X. Return 0 if X isn't valid for MODE. */ 1370 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1005 1371
1006 static int 1372 static int
1007 microblaze_address_insns (rtx x, enum machine_mode mode) 1373 microblaze_address_insns (rtx x, machine_mode mode)
1008 { 1374 {
1009 struct microblaze_address_info addr; 1375 struct microblaze_address_info addr;
1010 1376
1011 if (microblaze_classify_address (&addr, x, mode, false)) 1377 if (microblaze_classify_address (&addr, x, mode, false))
1012 { 1378 {
1021 if (SMALL_INT (x)) 1387 if (SMALL_INT (x))
1022 return 1; 1388 return 1;
1023 else 1389 else
1024 return 2; 1390 return 2;
1025 case ADDRESS_REG_INDEX: 1391 case ADDRESS_REG_INDEX:
1392 return 1;
1026 case ADDRESS_SYMBOLIC: 1393 case ADDRESS_SYMBOLIC:
1027 return 1;
1028 case ADDRESS_GOTOFF: 1394 case ADDRESS_GOTOFF:
1029 return 2; 1395 return 2;
1396 case ADDRESS_TLS:
1397 switch (addr.tls_type)
1398 {
1399 case TLS_GD:
1400 return 2;
1401 case TLS_LDM:
1402 return 2;
1403 case TLS_DTPREL:
1404 return 1;
1405 default :
1406 abort();
1407 }
1030 default: 1408 default:
1031 break; 1409 break;
1032 } 1410 }
1033 } 1411 }
1034 return 0; 1412 return 0;
1035 } 1413 }
1036 1414
1037 /* Provide the costs of an addressing mode that contains ADDR. 1415 /* Provide the costs of an addressing mode that contains ADDR.
1038 If ADDR is not a valid address, its cost is irrelevant. */ 1416 If ADDR is not a valid address, its cost is irrelevant. */
1039 static int 1417 static int
1040 microblaze_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED) 1418 microblaze_address_cost (rtx addr, machine_mode mode ATTRIBUTE_UNUSED,
1419 addr_space_t as ATTRIBUTE_UNUSED,
1420 bool speed ATTRIBUTE_UNUSED)
1041 { 1421 {
1042 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr))); 1422 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1043 } 1423 }
1044 1424
1045 /* Return nonzero if X is an address which needs a temporary register when 1425 /* Return nonzero if X is an address which needs a temporary register when
1046 reloaded while generating PIC code. */ 1426 reloaded while generating PIC code. */
1047 1427
1048 int 1428 int
1049 pic_address_needs_scratch (rtx x) 1429 pic_address_needs_scratch (rtx x)
1050 { 1430 {
1051 /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ 1431 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
1052 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS 1432 {
1053 && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF 1433 rtx p0, p1;
1054 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT 1434
1055 && (flag_pic == 2 || !SMALL_INT (XEXP (XEXP (x, 0), 1)))) 1435 p0 = XEXP (XEXP (x, 0), 0);
1056 return 1; 1436 p1 = XEXP (XEXP (x, 0), 1);
1057 1437
1438 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
1439 && (GET_CODE (p1) == CONST_INT)
1440 && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
1441 return 1;
1442 }
1058 return 0; 1443 return 0;
1059 } 1444 }
1060 1445
1061 /* Argument support functions. */ 1446 /* Argument support functions. */
1062 /* Initialize CUMULATIVE_ARGS for a function. */ 1447 /* Initialize CUMULATIVE_ARGS for a function. */
1085 } 1470 }
1086 1471
1087 /* Advance the argument to the next argument position. */ 1472 /* Advance the argument to the next argument position. */
1088 1473
1089 static void 1474 static void
1090 microblaze_function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode, 1475 microblaze_function_arg_advance (cumulative_args_t cum_v,
1476 machine_mode mode,
1091 const_tree type, bool named ATTRIBUTE_UNUSED) 1477 const_tree type, bool named ATTRIBUTE_UNUSED)
1092 { 1478 {
1479 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1480
1093 cum->arg_number++; 1481 cum->arg_number++;
1094 switch (mode) 1482 switch (mode)
1095 { 1483 {
1096 case VOIDmode: 1484 case E_VOIDmode:
1097 break; 1485 break;
1098 1486
1099 default: 1487 default:
1100 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT 1488 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1101 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT); 1489 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1103 cum->gp_reg_found = 1; 1491 cum->gp_reg_found = 1;
1104 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) 1492 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1105 / UNITS_PER_WORD); 1493 / UNITS_PER_WORD);
1106 break; 1494 break;
1107 1495
1108 case BLKmode: 1496 case E_BLKmode:
1109 cum->gp_reg_found = 1; 1497 cum->gp_reg_found = 1;
1110 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1) 1498 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1111 / UNITS_PER_WORD); 1499 / UNITS_PER_WORD);
1112 break; 1500 break;
1113 1501
1114 case SFmode: 1502 case E_SFmode:
1115 cum->arg_words++; 1503 cum->arg_words++;
1116 if (!cum->gp_reg_found && cum->arg_number <= 2) 1504 if (!cum->gp_reg_found && cum->arg_number <= 2)
1117 cum->fp_code += 1 << ((cum->arg_number - 1) * 2); 1505 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1118 break; 1506 break;
1119 1507
1120 case DFmode: 1508 case E_DFmode:
1121 cum->arg_words += 2; 1509 cum->arg_words += 2;
1122 if (!cum->gp_reg_found && cum->arg_number <= 2) 1510 if (!cum->gp_reg_found && cum->arg_number <= 2)
1123 cum->fp_code += 2 << ((cum->arg_number - 1) * 2); 1511 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1124 break; 1512 break;
1125 1513
1126 case DImode: 1514 case E_DImode:
1127 cum->gp_reg_found = 1; 1515 cum->gp_reg_found = 1;
1128 cum->arg_words += 2; 1516 cum->arg_words += 2;
1129 break; 1517 break;
1130 1518
1131 case QImode: 1519 case E_QImode:
1132 case HImode: 1520 case E_HImode:
1133 case SImode: 1521 case E_SImode:
1134 case TImode: 1522 case E_TImode:
1135 cum->gp_reg_found = 1; 1523 cum->gp_reg_found = 1;
1136 cum->arg_words++; 1524 cum->arg_words++;
1137 break; 1525 break;
1138 } 1526 }
1139 } 1527 }
1140 1528
1141 /* Return an RTL expression containing the register for the given mode, 1529 /* Return an RTL expression containing the register for the given mode,
1142 or 0 if the argument is to be passed on the stack. */ 1530 or 0 if the argument is to be passed on the stack. */
1143 1531
1144 static rtx 1532 static rtx
1145 microblaze_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode, 1533 microblaze_function_arg (cumulative_args_t cum_v, machine_mode mode,
1146 const_tree type ATTRIBUTE_UNUSED, 1534 const_tree type ATTRIBUTE_UNUSED,
1147 bool named ATTRIBUTE_UNUSED) 1535 bool named ATTRIBUTE_UNUSED)
1148 { 1536 {
1537 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1538
1149 rtx ret; 1539 rtx ret;
1150 int regbase = -1; 1540 int regbase = -1;
1151 int *arg_words = &cum->arg_words; 1541 int *arg_words = &cum->arg_words;
1152 1542
1153 cum->last_arg_fp = 0; 1543 cum->last_arg_fp = 0;
1154 switch (mode) 1544 switch (mode)
1155 { 1545 {
1156 case SFmode: 1546 case E_SFmode:
1157 case DFmode: 1547 case E_DFmode:
1158 case VOIDmode: 1548 case E_VOIDmode:
1159 case QImode: 1549 case E_QImode:
1160 case HImode: 1550 case E_HImode:
1161 case SImode: 1551 case E_SImode:
1162 case DImode: 1552 case E_DImode:
1163 case TImode: 1553 case E_TImode:
1164 regbase = GP_ARG_FIRST; 1554 regbase = GP_ARG_FIRST;
1165 break; 1555 break;
1166 default: 1556 default:
1167 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT 1557 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1168 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT); 1558 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1169 /* Drops through. */ 1559 /* FALLTHRU */
1170 case BLKmode: 1560 case E_BLKmode:
1171 regbase = GP_ARG_FIRST; 1561 regbase = GP_ARG_FIRST;
1172 break; 1562 break;
1173 } 1563 }
1174 1564
1175 if (*arg_words >= MAX_ARGS_IN_REGISTERS) 1565 if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1182 } 1572 }
1183 1573
1184 if (mode == VOIDmode) 1574 if (mode == VOIDmode)
1185 { 1575 {
1186 if (cum->num_adjusts > 0) 1576 if (cum->num_adjusts > 0)
1187 ret = gen_rtx_PARALLEL ((enum machine_mode) cum->fp_code, 1577 ret = gen_rtx_PARALLEL ((machine_mode) cum->fp_code,
1188 gen_rtvec_v (cum->num_adjusts, cum->adjust)); 1578 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1189 } 1579 }
1190 1580
1191 return ret; 1581 return ret;
1192 } 1582 }
1193 1583
1194 /* Return number of bytes of argument to put in registers. */ 1584 /* Return number of bytes of argument to put in registers. */
1195 static int 1585 static int
1196 function_arg_partial_bytes (CUMULATIVE_ARGS * cum, enum machine_mode mode, 1586 function_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
1197 tree type, bool named ATTRIBUTE_UNUSED) 1587 tree type, bool named ATTRIBUTE_UNUSED)
1198 { 1588 {
1589 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1590
1199 if ((mode == BLKmode 1591 if ((mode == BLKmode
1200 || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT 1592 || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1201 || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) 1593 || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1202 && cum->arg_words < MAX_ARGS_IN_REGISTERS) 1594 && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1203 { 1595 {
1224 for easier range comparison. */ 1616 for easier range comparison. */
1225 static int 1617 static int
1226 microblaze_version_to_int (const char *version) 1618 microblaze_version_to_int (const char *version)
1227 { 1619 {
1228 const char *p, *v; 1620 const char *p, *v;
1229 const char *tmpl = "vX.YY.Z"; 1621 const char *tmpl = "vXX.YY.Z";
1230 int iver = 0; 1622 int iver = 0;
1231 1623
1232 p = version; 1624 p = version;
1233 v = tmpl; 1625 v = tmpl;
1234 1626
1235 while (*v) 1627 while (*p)
1236 { 1628 {
1237 if (*v == 'X') 1629 if (*v == 'X')
1238 { /* Looking for major */ 1630 { /* Looking for major */
1239 if (!(*p >= '0' && *p <= '9')) 1631 if (*p == '.')
1240 return -1; 1632 {
1241 iver += (int) (*p - '0'); 1633 v++;
1242 iver *= 10; 1634 }
1243 } 1635 else
1636 {
1637 if (!(*p >= '0' && *p <= '9'))
1638 return -1;
1639 iver += (int) (*p - '0');
1640 iver *= 10;
1641 }
1642 }
1244 else if (*v == 'Y') 1643 else if (*v == 'Y')
1245 { /* Looking for minor */ 1644 { /* Looking for minor */
1246 if (!(*p >= '0' && *p <= '9')) 1645 if (!(*p >= '0' && *p <= '9'))
1247 return -1; 1646 return -1;
1248 iver += (int) (*p - '0'); 1647 iver += (int) (*p - '0');
1269 return -1; 1668 return -1;
1270 1669
1271 return iver; 1670 return iver;
1272 } 1671 }
1273 1672
1274 static bool
1275 microblaze_handle_option (size_t code,
1276 const char *arg ATTRIBUTE_UNUSED,
1277 int value ATTRIBUTE_UNUSED)
1278 {
1279 switch (code)
1280 {
1281 case OPT_mno_clearbss:
1282 flag_zero_initialized_in_bss = 0;
1283 warning (0, "-mno-clearbss is deprecated; use -fno-zero-initialized-in-bss");
1284 break;
1285 case OPT_mxl_stack_check:
1286 warning (0, "-mxl_stack_check is deprecated; use -fstack-check");
1287 break;
1288 }
1289 return true;
1290 }
1291
1292 1673
1293 static void 1674 static void
1294 microblaze_option_override (void) 1675 microblaze_option_override (void)
1295 { 1676 {
1296 register int i, start; 1677 register int i, start;
1297 register int regno; 1678 register int regno;
1298 register enum machine_mode mode; 1679 register machine_mode mode;
1299 int ver; 1680 int ver;
1300 1681
1301 microblaze_section_threshold = (global_options_set.x_g_switch_value 1682 microblaze_section_threshold = (global_options_set.x_g_switch_value
1302 ? g_switch_value 1683 ? g_switch_value
1303 : MICROBLAZE_DEFAULT_GVALUE); 1684 : MICROBLAZE_DEFAULT_GVALUE);
1685
1686 if (flag_pic)
1687 {
1688 /* Make sure it's 2, we only support one kind of PIC. */
1689 flag_pic = 2;
1690 if (!TARGET_SUPPORTS_PIC)
1691 {
1692 error ("-fPIC/-fpic not supported for this target");
1693 /* Clear it to avoid further errors. */
1694 flag_pic = 0;
1695 }
1696 }
1304 1697
1305 /* Check the MicroBlaze CPU version for any special action to be done. */ 1698 /* Check the MicroBlaze CPU version for any special action to be done. */
1306 if (microblaze_select_cpu == NULL) 1699 if (microblaze_select_cpu == NULL)
1307 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU; 1700 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1308 ver = microblaze_version_to_int (microblaze_select_cpu); 1701 ver = microblaze_version_to_int (microblaze_select_cpu);
1356 if (ver < 0) 1749 if (ver < 0)
1357 { 1750 {
1358 if (TARGET_MULTIPLY_HIGH) 1751 if (TARGET_MULTIPLY_HIGH)
1359 warning (0, 1752 warning (0,
1360 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater"); 1753 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1754 }
1755
1756 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.10.a");
1757 microblaze_has_clz = 1;
1758 if (ver < 0)
1759 {
1760 /* MicroBlaze prior to 8.10.a didn't have clz. */
1761 microblaze_has_clz = 0;
1762 }
1763
1764 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1765 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.30.a");
1766 if (ver < 0)
1767 {
1768 if (TARGET_REORDER == 1)
1769 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1770 TARGET_REORDER = 0;
1771 }
1772 else if ((ver == 0) && !TARGET_PATTERN_COMPARE)
1773 {
1774 if (TARGET_REORDER == 1)
1775 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1776 TARGET_REORDER = 0;
1361 } 1777 }
1362 1778
1363 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL) 1779 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1364 error ("-mxl-multiply-high requires -mno-xl-soft-mul"); 1780 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1365 1781
1406 microblaze_dbx_regno[i] = i + start; 1822 microblaze_dbx_regno[i] = i + start;
1407 1823
1408 /* Set up array giving whether a given register can hold a given mode. */ 1824 /* Set up array giving whether a given register can hold a given mode. */
1409 1825
1410 for (mode = VOIDmode; 1826 for (mode = VOIDmode;
1411 mode != MAX_MACHINE_MODE; mode = (enum machine_mode) ((int) mode + 1)) 1827 mode != MAX_MACHINE_MODE; mode = (machine_mode) ((int) mode + 1))
1412 { 1828 {
1413 register int size = GET_MODE_SIZE (mode); 1829 register int size = GET_MODE_SIZE (mode);
1414 1830
1415 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) 1831 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1416 { 1832 {
1423 else if (GP_REG_P (regno)) 1839 else if (GP_REG_P (regno))
1424 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD); 1840 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1425 else 1841 else
1426 ok = 0; 1842 ok = 0;
1427 1843
1428 microblaze_hard_regno_mode_ok[(int) mode][regno] = ok; 1844 microblaze_hard_regno_mode_ok_p[(int) mode][regno] = ok;
1429 } 1845 }
1430 } 1846 }
1431 } 1847 }
1432 1848
1433 /* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ 1849 /* Implement TARGET_HARD_REGNO_MODE_OK. In 32 bit mode, require that
1434 static const struct default_options microblaze_option_optimization_table[] = 1850 DImode and DFmode be in even registers. For DImode, this makes some
1435 { 1851 of the insns easier to write, since you don't have to worry about a
1436 { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 }, 1852 DImode value in registers 3 & 4, producing a result in 4 & 5.
1437 { OPT_LEVELS_NONE, 0, NULL, 0 } 1853
1438 }; 1854 To make the code simpler, the hook now just references an
1855 array built in override_options. */
1856
1857 static bool
1858 microblaze_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
1859 {
1860 return microblaze_hard_regno_mode_ok_p[mode][regno];
1861 }
1862
1863 /* Implement TARGET_MODES_TIEABLE_P. */
1864
1865 static bool
1866 microblaze_modes_tieable_p (machine_mode mode1, machine_mode mode2)
1867 {
1868 return ((GET_MODE_CLASS (mode1) == MODE_FLOAT
1869 || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)
1870 == (GET_MODE_CLASS (mode2) == MODE_FLOAT
1871 || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
1872 }
1439 1873
1440 /* Return true if FUNC is an interrupt function as specified 1874 /* Return true if FUNC is an interrupt function as specified
1441 by the "interrupt_handler" attribute. */ 1875 by the "interrupt_handler" attribute. */
1442 1876
1443 static int 1877 static int
1450 1884
1451 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func)); 1885 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1452 return a != NULL_TREE; 1886 return a != NULL_TREE;
1453 } 1887 }
1454 1888
1889 static int
1890 microblaze_fast_interrupt_function_p (tree func)
1891 {
1892 tree a;
1893
1894 if (TREE_CODE (func) != FUNCTION_DECL)
1895 return 0;
1896
1897 a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func));
1898 return a != NULL_TREE;
1899 }
1900 int
1901 microblaze_break_function_p (tree func)
1902 {
1903 tree a;
1904 if (!func)
1905 return 0;
1906 if (TREE_CODE (func) != FUNCTION_DECL)
1907 return 0;
1908
1909 a = lookup_attribute ("break_handler", DECL_ATTRIBUTES (func));
1910 return a != NULL_TREE;
1911 }
1455 /* Return true if FUNC is an interrupt function which uses 1912 /* Return true if FUNC is an interrupt function which uses
1456 normal return, indicated by the "save_volatiles" attribute. */ 1913 normal return, indicated by the "save_volatiles" attribute. */
1457 1914
1458 static int 1915 static int
1459 microblaze_save_volatiles (tree func) 1916 microblaze_save_volatiles (tree func)
1466 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func)); 1923 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1467 return a != NULL_TREE; 1924 return a != NULL_TREE;
1468 } 1925 }
1469 1926
1470 /* Return whether function is tagged with 'interrupt_handler' 1927 /* Return whether function is tagged with 'interrupt_handler'
1471 attribute. Return true if function should use return from 1928 or 'fast_interrupt' attribute. Return true if function
1472 interrupt rather than normal function return. */ 1929 should use return from interrupt rather than normal
1930 function return. */
1473 int 1931 int
1474 microblaze_is_interrupt_handler (void) 1932 microblaze_is_interrupt_variant (void)
1475 { 1933 {
1476 return interrupt_handler; 1934 return (interrupt_handler || fast_interrupt);
1935 }
1936 int
1937 microblaze_is_break_handler (void)
1938 {
1939 return break_handler;
1477 } 1940 }
1478 1941
1479 /* Determine of register must be saved/restored in call. */ 1942 /* Determine of register must be saved/restored in call. */
1480 static int 1943 static int
1481 microblaze_must_save_register (int regno) 1944 microblaze_must_save_register (int regno)
1488 return 1; 1951 return 1;
1489 1952
1490 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM)) 1953 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1491 return 1; 1954 return 1;
1492 1955
1493 if (!current_function_is_leaf) 1956 if (crtl->calls_eh_return
1957 && regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1958 return 1;
1959
1960 if (!crtl->is_leaf)
1494 { 1961 {
1495 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM) 1962 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1496 return 1; 1963 return 1;
1497 if ((interrupt_handler || save_volatiles) && 1964 if ((microblaze_is_interrupt_variant () || save_volatiles) &&
1498 (regno >= 3 && regno <= 12)) 1965 (regno >= 3 && regno <= 12))
1499 return 1; 1966 return 1;
1500 } 1967 }
1501 1968
1502 if (interrupt_handler) 1969 if (microblaze_is_interrupt_variant ())
1503 { 1970 {
1504 if (df_regs_ever_live_p (regno) 1971 if (df_regs_ever_live_p (regno)
1505 || regno == MB_ABI_MSR_SAVE_REG 1972 || regno == MB_ABI_MSR_SAVE_REG
1506 || regno == MB_ABI_ASM_TEMP_REGNUM 1973 || (interrupt_handler
1507 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM) 1974 && (regno == MB_ABI_ASM_TEMP_REGNUM
1975 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)))
1508 return 1; 1976 return 1;
1509 } 1977 }
1510 1978
1511 if (save_volatiles) 1979 if (save_volatiles)
1512 { 1980 {
1513 if (df_regs_ever_live_p (regno) 1981 if (df_regs_ever_live_p (regno)
1514 || regno == MB_ABI_ASM_TEMP_REGNUM 1982 || regno == MB_ABI_ASM_TEMP_REGNUM
1515 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM) 1983 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1516 return 1; 1984 return 1;
1517 } 1985 }
1986
1987 if (crtl->calls_eh_return
1988 && (regno == EH_RETURN_DATA_REGNO (0)
1989 || regno == EH_RETURN_DATA_REGNO (1)))
1990 return 1;
1518 1991
1519 return 0; 1992 return 0;
1520 } 1993 }
1521 1994
1522 /* Return the bytes needed to compute the frame pointer from the current 1995 /* Return the bytes needed to compute the frame pointer from the current
1575 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */ 2048 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
1576 long mask; /* mask of saved gp registers. */ 2049 long mask; /* mask of saved gp registers. */
1577 2050
1578 interrupt_handler = 2051 interrupt_handler =
1579 microblaze_interrupt_function_p (current_function_decl); 2052 microblaze_interrupt_function_p (current_function_decl);
2053 break_handler =
2054 microblaze_break_function_p (current_function_decl);
2055
2056 fast_interrupt =
2057 microblaze_fast_interrupt_function_p (current_function_decl);
1580 save_volatiles = microblaze_save_volatiles (current_function_decl); 2058 save_volatiles = microblaze_save_volatiles (current_function_decl);
2059 if (break_handler)
2060 interrupt_handler = break_handler;
1581 2061
1582 gp_reg_size = 0; 2062 gp_reg_size = 0;
1583 mask = 0; 2063 mask = 0;
1584 var_size = size; 2064 var_size = size;
1585 args_size = crtl->outgoing_args_size; 2065 args_size = crtl->outgoing_args_size;
1608 } 2088 }
1609 2089
1610 total_size += gp_reg_size; 2090 total_size += gp_reg_size;
1611 2091
1612 /* Add 4 bytes for MSR. */ 2092 /* Add 4 bytes for MSR. */
1613 if (interrupt_handler) 2093 if (microblaze_is_interrupt_variant ())
1614 total_size += 4; 2094 total_size += 4;
1615 2095
1616 /* No space to be allocated for link register in leaf functions with no other 2096 /* No space to be allocated for link register in leaf functions with no other
1617 stack requirements. */ 2097 stack requirements. */
1618 if (total_size == 0 && current_function_is_leaf) 2098 if (total_size == 0 && crtl->is_leaf)
1619 link_debug_size = 0; 2099 link_debug_size = 0;
1620 else 2100 else
1621 link_debug_size = UNITS_PER_WORD; 2101 link_debug_size = UNITS_PER_WORD;
1622 2102
1623 total_size += link_debug_size; 2103 total_size += link_debug_size;
1674 offset = compute_frame_size (get_frame_size ()); 2154 offset = compute_frame_size (get_frame_size ());
1675 else 2155 else
1676 gcc_unreachable (); 2156 gcc_unreachable ();
1677 break; 2157 break;
1678 case RETURN_ADDRESS_POINTER_REGNUM: 2158 case RETURN_ADDRESS_POINTER_REGNUM:
1679 if (current_function_is_leaf) 2159 if (crtl->is_leaf)
1680 offset = 0; 2160 offset = 0;
1681 else 2161 else
1682 offset = current_frame_info.gp_offset + 2162 offset = current_frame_info.gp_offset +
1683 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT))); 2163 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
1684 break; 2164 break;
1707 'b' print 'n' for EQ, 'z' for NE 2187 'b' print 'n' for EQ, 'z' for NE
1708 'T' print 'f' for EQ, 't' for NE 2188 'T' print 'f' for EQ, 't' for NE
1709 't' print 't' for EQ, 'f' for NE 2189 't' print 't' for EQ, 'f' for NE
1710 'm' Print 1<<operand. 2190 'm' Print 1<<operand.
1711 'i' Print 'i' if MEM operand has immediate value 2191 'i' Print 'i' if MEM operand has immediate value
2192 'y' Print 'y' if MEM operand is single register
1712 'o' Print operand address+4 2193 'o' Print operand address+4
1713 '?' Print 'd' if we use a branch with delay slot instead of normal branch. 2194 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
1714 'h' Print high word of const_double (int or float) value as hex 2195 'h' Print high word of const_double (int or float) value as hex
1715 'j' Print low word of const_double (int or float) value as hex 2196 'j' Print low word of const_double (int or float) value as hex
1716 's' Print -1 if operand is negative, 0 if positive (sign extend) 2197 's' Print -1 if operand is negative, 0 if positive (sign extend)
1843 { 2324 {
1844 case ADDRESS_REG: 2325 case ADDRESS_REG:
1845 case ADDRESS_CONST_INT: 2326 case ADDRESS_CONST_INT:
1846 case ADDRESS_SYMBOLIC: 2327 case ADDRESS_SYMBOLIC:
1847 case ADDRESS_GOTOFF: 2328 case ADDRESS_GOTOFF:
2329 case ADDRESS_TLS:
1848 fputs ("i", file); 2330 fputs ("i", file);
1849 break; 2331 break;
1850 case ADDRESS_REG_INDEX: 2332 case ADDRESS_REG_INDEX:
1851 break; 2333 break;
1852 case ADDRESS_INVALID: 2334 case ADDRESS_INVALID:
1874 2356
1875 else if (code == MEM) 2357 else if (code == MEM)
1876 if (letter == 'o') 2358 if (letter == 'o')
1877 { 2359 {
1878 rtx op4 = adjust_address (op, GET_MODE (op), 4); 2360 rtx op4 = adjust_address (op, GET_MODE (op), 4);
1879 output_address (XEXP (op4, 0)); 2361 output_address (GET_MODE (op), XEXP (op4, 0));
2362 }
2363 else if (letter == 'y')
2364 {
2365 rtx mem_reg = XEXP (op, 0);
2366 if (GET_CODE (mem_reg) == REG)
2367 {
2368 register int regnum = REGNO (mem_reg);
2369 fprintf (file, "%s", reg_names[regnum]);
2370 }
1880 } 2371 }
1881 else 2372 else
1882 output_address (XEXP (op, 0)); 2373 output_address (GET_MODE (op), XEXP (op, 0));
1883 2374
1884 else if (letter == 'h' || letter == 'j') 2375 else if (letter == 'h' || letter == 'j')
1885 { 2376 {
1886 long val[2]; 2377 long val[2];
1887 if (code == CONST_DOUBLE) 2378 if (code == CONST_DOUBLE)
1888 { 2379 {
1889 if (GET_MODE (op) == DFmode) 2380 if (GET_MODE (op) == DFmode)
1890 { 2381 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op), val);
1891 REAL_VALUE_TYPE value;
1892 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
1893 REAL_VALUE_TO_TARGET_DOUBLE (value, val);
1894 }
1895 else 2382 else
1896 { 2383 {
1897 val[0] = CONST_DOUBLE_HIGH (op); 2384 val[0] = CONST_DOUBLE_HIGH (op);
1898 val[1] = CONST_DOUBLE_LOW (op); 2385 val[1] = CONST_DOUBLE_LOW (op);
1899 } 2386 }
1911 else if (code == CONST_DOUBLE) 2398 else if (code == CONST_DOUBLE)
1912 { 2399 {
1913 if (letter == 'F') 2400 if (letter == 'F')
1914 { 2401 {
1915 unsigned long value_long; 2402 unsigned long value_long;
1916 REAL_VALUE_TYPE value; 2403 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op),
1917 REAL_VALUE_FROM_CONST_DOUBLE (value, op); 2404 value_long);
1918 REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
1919 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long); 2405 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
1920 } 2406 }
1921 else 2407 else
1922 { 2408 {
1923 char s[60]; 2409 char s[60];
1959 else if (letter == 'T') 2445 else if (letter == 'T')
1960 fputs (code == EQ ? "f" : "t", file); 2446 fputs (code == EQ ? "f" : "t", file);
1961 else if (letter == 't') 2447 else if (letter == 't')
1962 fputs (code == EQ ? "t" : "f", file); 2448 fputs (code == EQ ? "t" : "f", file);
1963 2449
1964 else if (code == CONST && GET_CODE (XEXP (op, 0)) == REG) 2450 else if (code == CONST
2451 && ((GET_CODE (XEXP (op, 0)) == REG)
2452 || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
1965 { 2453 {
1966 print_operand (file, XEXP (op, 0), letter); 2454 print_operand (file, XEXP (op, 0), letter);
2455 }
2456 else if (code == CONST
2457 && (GET_CODE (XEXP (op, 0)) == PLUS)
2458 && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
2459 && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
2460 {
2461 print_operand_address (file, XEXP (op, 0));
1967 } 2462 }
1968 else if (letter == 'm') 2463 else if (letter == 'm')
1969 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op))); 2464 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
1970 else 2465 else
1971 output_addr_const (file, op); 2466 output_addr_const (file, op);
2023 output_addr_const (file, info.offset); 2518 output_addr_const (file, info.offset);
2024 break; 2519 break;
2025 case ADDRESS_SYMBOLIC: 2520 case ADDRESS_SYMBOLIC:
2026 case ADDRESS_GOTOFF: 2521 case ADDRESS_GOTOFF:
2027 case ADDRESS_PLT: 2522 case ADDRESS_PLT:
2523 case ADDRESS_TLS:
2028 if (info.regA) 2524 if (info.regA)
2029 fprintf (file, "%s,", reg_names[REGNO (info.regA)]); 2525 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2030 output_addr_const (file, info.symbol); 2526 output_addr_const (file, info.symbol);
2031 if (type == ADDRESS_GOTOFF) 2527 if (type == ADDRESS_GOTOFF)
2032 { 2528 {
2034 } 2530 }
2035 else if (type == ADDRESS_PLT) 2531 else if (type == ADDRESS_PLT)
2036 { 2532 {
2037 fputs ("@PLT", file); 2533 fputs ("@PLT", file);
2038 } 2534 }
2535 else if (type == ADDRESS_TLS)
2536 {
2537 switch (info.tls_type)
2538 {
2539 case TLS_GD:
2540 fputs ("@TLSGD", file);
2541 break;
2542 case TLS_LDM:
2543 fputs ("@TLSLDM", file);
2544 break;
2545 case TLS_DTPREL:
2546 fputs ("@TLSDTPREL", file);
2547 break;
2548 default :
2549 abort();
2550 break;
2551 }
2552 }
2039 break; 2553 break;
2040 case ADDRESS_INVALID: 2554 case ADDRESS_INVALID:
2041 fatal_insn ("invalid address", addr); 2555 fatal_insn ("invalid address", addr);
2042 break; 2556 break;
2043 } 2557 }
2100 gcc_assert (gp_offset > 0); 2614 gcc_assert (gp_offset > 0);
2101 2615
2102 base_reg_rtx = stack_pointer_rtx; 2616 base_reg_rtx = stack_pointer_rtx;
2103 2617
2104 /* For interrupt_handlers, need to save/restore the MSR. */ 2618 /* For interrupt_handlers, need to save/restore the MSR. */
2105 if (interrupt_handler) 2619 if (microblaze_is_interrupt_variant ())
2106 { 2620 {
2107 isr_mem_rtx = gen_rtx_MEM (SImode, 2621 isr_mem_rtx = gen_rtx_MEM (SImode,
2108 gen_rtx_PLUS (Pmode, base_reg_rtx, 2622 gen_rtx_PLUS (Pmode, base_reg_rtx,
2109 GEN_INT (current_frame_info. 2623 GEN_INT (current_frame_info.
2110 gp_offset - 2624 gp_offset -
2114 MEM_VOLATILE_P (isr_mem_rtx) = 1; 2628 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2115 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG); 2629 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2116 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG); 2630 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2117 } 2631 }
2118 2632
2119 if (interrupt_handler && !prologue) 2633 if (microblaze_is_interrupt_variant () && !prologue)
2120 { 2634 {
2121 emit_move_insn (isr_reg_rtx, isr_mem_rtx); 2635 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2122 emit_move_insn (isr_msr_rtx, isr_reg_rtx); 2636 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2123 /* Do not optimize in flow analysis. */ 2637 /* Do not optimize in flow analysis. */
2124 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx)); 2638 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2134 continue; 2648 continue;
2135 2649
2136 reg_rtx = gen_rtx_REG (SImode, regno); 2650 reg_rtx = gen_rtx_REG (SImode, regno);
2137 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset)); 2651 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2138 mem_rtx = gen_rtx_MEM (SImode, insn); 2652 mem_rtx = gen_rtx_MEM (SImode, insn);
2139 if (interrupt_handler || save_volatiles) 2653 if (microblaze_is_interrupt_variant () || save_volatiles)
2140 /* Do not optimize in flow analysis. */ 2654 /* Do not optimize in flow analysis. */
2141 MEM_VOLATILE_P (mem_rtx) = 1; 2655 MEM_VOLATILE_P (mem_rtx) = 1;
2142 2656
2143 if (prologue) 2657 if (prologue)
2144 { 2658 {
2152 2666
2153 gp_offset += GET_MODE_SIZE (SImode); 2667 gp_offset += GET_MODE_SIZE (SImode);
2154 } 2668 }
2155 } 2669 }
2156 2670
2157 if (interrupt_handler && prologue) 2671 if (microblaze_is_interrupt_variant () && prologue)
2158 { 2672 {
2159 emit_move_insn (isr_reg_rtx, isr_msr_rtx); 2673 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2160 emit_move_insn (isr_mem_rtx, isr_reg_rtx); 2674 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2161 2675
2162 /* Do not optimize in flow analysis. */ 2676 /* Do not optimize in flow analysis. */
2168 } 2682 }
2169 2683
2170 2684
2171 /* Set up the stack and frame (if desired) for the function. */ 2685 /* Set up the stack and frame (if desired) for the function. */
2172 static void 2686 static void
2173 microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) 2687 microblaze_function_prologue (FILE * file)
2174 { 2688 {
2175 const char *fnname; 2689 const char *fnname;
2176 long fsiz = current_frame_info.total_size; 2690 long fsiz = current_frame_info.total_size;
2177 2691
2178 /* Get the function name the same way that toplev.c does before calling 2692 /* Get the function name the same way that toplev.c does before calling
2181 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); 2695 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2182 if (!flag_inhibit_size_directive) 2696 if (!flag_inhibit_size_directive)
2183 { 2697 {
2184 fputs ("\t.ent\t", file); 2698 fputs ("\t.ent\t", file);
2185 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname)) 2699 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2186 fputs ("_interrupt_handler", file); 2700 fputs ("_interrupt_handler", file);
2701 else if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2702 fputs ("_break_handler", file);
2703 else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname))
2704 fputs ("_fast_interrupt", file);
2187 else 2705 else
2188 assemble_name (file, fnname); 2706 assemble_name (file, fnname);
2189 fputs ("\n", file); 2707 fputs ("\n", file);
2190 if (!interrupt_handler) 2708 if (!microblaze_is_interrupt_variant ())
2191 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function"); 2709 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2192 } 2710 }
2193 2711
2194 assemble_name (file, fnname); 2712 assemble_name (file, fnname);
2195 fputs (":\n", file); 2713 fputs (":\n", file);
2196 2714
2197 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname)) 2715 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2198 fputs ("_interrupt_handler:\n", file); 2716 fputs ("_interrupt_handler:\n", file);
2199 2717 if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2718 fputs ("_break_handler:\n", file);
2200 if (!flag_inhibit_size_directive) 2719 if (!flag_inhibit_size_directive)
2201 { 2720 {
2202 /* .frame FRAMEREG, FRAMESIZE, RETREG. */ 2721 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2203 fprintf (file, 2722 fprintf (file,
2204 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n", 2723 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2224 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t"); 2743 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2225 fprintf (file, "# Stack Check Stub -- End.\n"); 2744 fprintf (file, "# Stack Check Stub -- End.\n");
2226 } 2745 }
2227 } 2746 }
2228 2747
2748 static void
2749 microblaze_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
2750 {
2751 section *s;
2752
2753 if (priority != DEFAULT_INIT_PRIORITY)
2754 {
2755 char buf[18];
2756 sprintf (buf, "%s.%.5u",
2757 is_ctor ? ".ctors" : ".dtors",
2758 MAX_INIT_PRIORITY - priority);
2759 s = get_section (buf, SECTION_WRITE, NULL_TREE);
2760 }
2761 else if (is_ctor)
2762 s = ctors_section;
2763 else
2764 s = dtors_section;
2765
2766 switch_to_section (s);
2767 assemble_align (POINTER_SIZE);
2768 fputs ("\t.word\t", asm_out_file);
2769 output_addr_const (asm_out_file, symbol);
2770 fputs ("\n", asm_out_file);
2771 }
2772
2773 /* Add a function to the list of static constructors. */
2774
2775 static void
2776 microblaze_elf_asm_constructor (rtx symbol, int priority)
2777 {
2778 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/true);
2779 }
2780
2781 /* Add a function to the list of static destructors. */
2782
2783 static void
2784 microblaze_elf_asm_destructor (rtx symbol, int priority)
2785 {
2786 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false);
2787 }
2788
2229 /* Expand the prologue into a bunch of separate insns. */ 2789 /* Expand the prologue into a bunch of separate insns. */
2230 2790
2231 void 2791 void
2232 microblaze_expand_prologue (void) 2792 microblaze_expand_prologue (void)
2233 { 2793 {
2239 tree fnargs = DECL_ARGUMENTS (fndecl); 2799 tree fnargs = DECL_ARGUMENTS (fndecl);
2240 rtx next_arg_reg; 2800 rtx next_arg_reg;
2241 int i; 2801 int i;
2242 tree next_arg; 2802 tree next_arg;
2243 tree cur_arg; 2803 tree cur_arg;
2244 CUMULATIVE_ARGS args_so_far; 2804 CUMULATIVE_ARGS args_so_far_v;
2805 cumulative_args_t args_so_far;
2245 rtx mem_rtx, reg_rtx; 2806 rtx mem_rtx, reg_rtx;
2246 2807
2247 /* If struct value address is treated as the first argument, make it so. */ 2808 /* If struct value address is treated as the first argument, make it so. */
2248 if (aggregate_value_p (DECL_RESULT (fndecl), fntype) 2809 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2249 && !cfun->returns_pcc_struct) 2810 && !cfun->returns_pcc_struct)
2257 fnargs = function_result_decl; 2818 fnargs = function_result_decl;
2258 } 2819 }
2259 2820
2260 /* Determine the last argument, and get its name. */ 2821 /* Determine the last argument, and get its name. */
2261 2822
2262 INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0, 0); 2823 INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
2824 args_so_far = pack_cumulative_args (&args_so_far_v);
2263 regno = GP_ARG_FIRST; 2825 regno = GP_ARG_FIRST;
2264 2826
2265 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg) 2827 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2266 { 2828 {
2267 tree passed_type = DECL_ARG_TYPE (cur_arg); 2829 tree passed_type = DECL_ARG_TYPE (cur_arg);
2268 enum machine_mode passed_mode = TYPE_MODE (passed_type); 2830 machine_mode passed_mode = TYPE_MODE (passed_type);
2269 rtx entry_parm; 2831 rtx entry_parm;
2270 2832
2271 if (TREE_ADDRESSABLE (passed_type)) 2833 if (TREE_ADDRESSABLE (passed_type))
2272 { 2834 {
2273 passed_type = build_pointer_type (passed_type); 2835 passed_type = build_pointer_type (passed_type);
2274 passed_mode = Pmode; 2836 passed_mode = Pmode;
2275 } 2837 }
2276 2838
2277 entry_parm = targetm.calls.function_arg (&args_so_far, passed_mode, 2839 entry_parm = targetm.calls.function_arg (args_so_far, passed_mode,
2278 passed_type, true); 2840 passed_type, true);
2279 2841
2280 if (entry_parm) 2842 if (entry_parm)
2281 { 2843 {
2282 int words; 2844 int words;
2293 { 2855 {
2294 regno = GP_ARG_LAST + 1; 2856 regno = GP_ARG_LAST + 1;
2295 break; 2857 break;
2296 } 2858 }
2297 2859
2298 targetm.calls.function_arg_advance (&args_so_far, passed_mode, 2860 targetm.calls.function_arg_advance (args_so_far, passed_mode,
2299 passed_type, true); 2861 passed_type, true);
2300 2862
2301 next_arg = TREE_CHAIN (cur_arg); 2863 next_arg = TREE_CHAIN (cur_arg);
2302 if (next_arg == 0) 2864 if (next_arg == 0)
2303 { 2865 {
2308 } 2870 }
2309 } 2871 }
2310 2872
2311 /* Split parallel insn into a sequence of insns. */ 2873 /* Split parallel insn into a sequence of insns. */
2312 2874
2313 next_arg_reg = targetm.calls.function_arg (&args_so_far, VOIDmode, 2875 next_arg_reg = targetm.calls.function_arg (args_so_far, VOIDmode,
2314 void_type_node, true); 2876 void_type_node, true);
2315 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL) 2877 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2316 { 2878 {
2317 rtvec adjust = XVEC (next_arg_reg, 0); 2879 rtvec adjust = XVEC (next_arg_reg, 0);
2318 int num = GET_NUM_ELEM (adjust); 2880 int num = GET_NUM_ELEM (adjust);
2323 emit_insn (pattern); 2885 emit_insn (pattern);
2324 } 2886 }
2325 } 2887 }
2326 2888
2327 fsiz = compute_frame_size (get_frame_size ()); 2889 fsiz = compute_frame_size (get_frame_size ());
2890
2891 if (flag_stack_usage_info)
2892 current_function_static_stack_size = fsiz;
2893
2328 2894
2329 /* If this function is a varargs function, store any registers that 2895 /* If this function is a varargs function, store any registers that
2330 would normally hold arguments ($5 - $10) on the stack. */ 2896 would normally hold arguments ($5 - $10) on the stack. */
2331 if (((TYPE_ARG_TYPES (fntype) != 0 2897 if (((TYPE_ARG_TYPES (fntype) != 0
2332 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) 2898 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2355 2921
2356 if (fsiz > 0) 2922 if (fsiz > 0)
2357 { 2923 {
2358 rtx fsiz_rtx = GEN_INT (fsiz); 2924 rtx fsiz_rtx = GEN_INT (fsiz);
2359 2925
2360 rtx insn = NULL; 2926 rtx_insn *insn = NULL;
2361 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, 2927 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2362 fsiz_rtx)); 2928 fsiz_rtx));
2363 if (insn) 2929 if (insn)
2364 RTX_FRAME_RELATED_P (insn) = 1; 2930 RTX_FRAME_RELATED_P (insn) = 1;
2365 2931
2366 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */ 2932 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2367 if (!current_function_is_leaf || interrupt_handler) 2933 if (!crtl->is_leaf || interrupt_handler)
2368 { 2934 {
2369 mem_rtx = gen_rtx_MEM (SImode, 2935 mem_rtx = gen_rtx_MEM (SImode,
2370 gen_rtx_PLUS (Pmode, stack_pointer_rtx, 2936 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2371 const0_rtx)); 2937 const0_rtx));
2372 2938
2382 /* _save_ registers for prologue. */ 2948 /* _save_ registers for prologue. */
2383 save_restore_insns (1); 2949 save_restore_insns (1);
2384 2950
2385 if (frame_pointer_needed) 2951 if (frame_pointer_needed)
2386 { 2952 {
2387 rtx insn = 0; 2953 rtx_insn *insn = 0;
2388 2954
2389 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx, 2955 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2390 stack_pointer_rtx)); 2956 stack_pointer_rtx));
2391 2957
2392 if (insn) 2958 if (insn)
2393 RTX_FRAME_RELATED_P (insn) = 1; 2959 RTX_FRAME_RELATED_P (insn) = 1;
2394 } 2960 }
2395 } 2961 }
2396 2962
2397 if (flag_pic == 2 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM)) 2963 if ((flag_pic == 2 || TLS_NEEDS_GOT )
2964 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
2398 { 2965 {
2399 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM); 2966 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
2400 emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */ 2967 emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
2401 } 2968 }
2402 2969
2411 2978
2412 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */ 2979 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2413 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST)) 2980 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2414 2981
2415 static void 2982 static void
2416 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED, 2983 microblaze_function_epilogue (FILE *file)
2417 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2418 { 2984 {
2419 const char *fnname; 2985 const char *fnname;
2420 2986
2421 /* Get the function name the same way that toplev.c does before calling 2987 /* Get the function name the same way that toplev.c does before calling
2422 assemble_start_function. This is needed so that the name used here 2988 assemble_start_function. This is needed so that the name used here
2424 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); 2990 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2425 2991
2426 if (!flag_inhibit_size_directive) 2992 if (!flag_inhibit_size_directive)
2427 { 2993 {
2428 fputs ("\t.end\t", file); 2994 fputs ("\t.end\t", file);
2429 if (interrupt_handler) 2995 if (interrupt_handler && !break_handler)
2430 fputs ("_interrupt_handler", file); 2996 fputs ("_interrupt_handler", file);
2997 else if (break_handler)
2998 fputs ("_break_handler", file);
2431 else 2999 else
2432 assemble_name (file, fnname); 3000 assemble_name (file, fnname);
2433 fputs ("\n", file); 3001 fputs ("\n", file);
2434 } 3002 }
2435 3003
2467 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the 3035 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
2468 sequence of load-followed by a use (in rtsd) in every prologue. Saves 3036 sequence of load-followed by a use (in rtsd) in every prologue. Saves
2469 a load-use stall cycle :) This is also important to handle alloca. 3037 a load-use stall cycle :) This is also important to handle alloca.
2470 (See comments for if (frame_pointer_needed) below. */ 3038 (See comments for if (frame_pointer_needed) below. */
2471 3039
2472 if (!current_function_is_leaf || interrupt_handler) 3040 if (!crtl->is_leaf || interrupt_handler)
2473 { 3041 {
2474 mem_rtx = 3042 mem_rtx =
2475 gen_rtx_MEM (SImode, 3043 gen_rtx_MEM (SImode,
2476 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx)); 3044 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
2477 if (interrupt_handler) 3045 if (interrupt_handler)
2494 save_restore_insns (0); 3062 save_restore_insns (0);
2495 emit_insn (gen_blockage ()); 3063 emit_insn (gen_blockage ());
2496 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx)); 3064 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
2497 } 3065 }
2498 3066
3067 if (crtl->calls_eh_return)
3068 emit_insn (gen_addsi3 (stack_pointer_rtx,
3069 stack_pointer_rtx,
3070 gen_raw_REG (SImode,
3071 MB_EH_STACKADJ_REGNUM)));
3072
2499 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST + 3073 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
2500 MB_ABI_SUB_RETURN_ADDR_REGNUM))); 3074 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2501 } 3075 }
2502 3076
2503 3077
2522 3096
2523 /* Implement TARGET_SECONDARY_RELOAD. */ 3097 /* Implement TARGET_SECONDARY_RELOAD. */
2524 3098
2525 static reg_class_t 3099 static reg_class_t
2526 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED, 3100 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
2527 reg_class_t rclass, enum machine_mode mode ATTRIBUTE_UNUSED, 3101 reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED,
2528 secondary_reload_info *sri ATTRIBUTE_UNUSED) 3102 secondary_reload_info *sri ATTRIBUTE_UNUSED)
2529 { 3103 {
2530 if (rclass == ST_REGS) 3104 if (rclass == ST_REGS)
2531 return GR_REGS; 3105 return GR_REGS;
2532 3106
2535 3109
2536 static void 3110 static void
2537 microblaze_globalize_label (FILE * stream, const char *name) 3111 microblaze_globalize_label (FILE * stream, const char *name)
2538 { 3112 {
2539 fputs ("\t.globl\t", stream); 3113 fputs ("\t.globl\t", stream);
2540 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME)) 3114 if (microblaze_is_interrupt_variant ())
2541 { 3115 {
2542 fputs (INTERRUPT_HANDLER_NAME, stream); 3116 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
3117 fputs (INTERRUPT_HANDLER_NAME, stream);
3118 else if (break_handler && strcmp (name, BREAK_HANDLER_NAME))
3119 fputs (BREAK_HANDLER_NAME, stream);
3120 else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME))
3121 fputs (FAST_INTERRUPT_NAME, stream);
2543 fputs ("\n\t.globl\t", stream); 3122 fputs ("\n\t.globl\t", stream);
2544 } 3123 }
2545 assemble_name (stream, name); 3124 assemble_name (stream, name);
2546 fputs ("\n", stream); 3125 fputs ("\n", stream);
2547 } 3126 }
2563 if (TREE_CODE (decl) == FUNCTION_DECL) 3142 if (TREE_CODE (decl) == FUNCTION_DECL)
2564 return false; 3143 return false;
2565 3144
2566 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl)) 3145 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
2567 { 3146 {
2568 const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); 3147 const char *section = DECL_SECTION_NAME (decl);
2569 if (strcmp (section, ".sdata") == 0 3148 if (strcmp (section, ".sdata") == 0
2570 || strcmp (section, ".sdata2") == 0 3149 || strcmp (section, ".sdata2") == 0
2571 || strcmp (section, ".sbss") == 0 3150 || strcmp (section, ".sbss") == 0
2572 || strcmp (section, ".sbss2") == 0) 3151 || strcmp (section, ".sbss2") == 0)
2573 return true; 3152 return true;
2606 { 3185 {
2607 default_encode_section_info (decl, rtl, first); 3186 default_encode_section_info (decl, rtl, first);
2608 } 3187 }
2609 3188
2610 static rtx 3189 static rtx
2611 expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED, rtx op) 3190 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED, rtx op)
2612 { 3191 {
2613 rtx result; 3192 rtx result;
2614 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF); 3193 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
2615 result = gen_rtx_CONST (Pmode, result); 3194 result = gen_rtx_CONST (Pmode, result);
2616 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result); 3195 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
2617 result = gen_const_mem (Pmode, result); 3196 result = gen_const_mem (Pmode, result);
2618 return result; 3197 return result;
2619 } 3198 }
2620 3199
3200 static void
3201 microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
3202 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
3203 tree function)
3204 {
3205 rtx this_rtx, funexp;
3206 rtx_insn *insn;
3207
3208 reload_completed = 1;
3209 epilogue_completed = 1;
3210
3211 /* Mark the end of the (empty) prologue. */
3212 emit_note (NOTE_INSN_PROLOGUE_END);
3213
3214 /* Find the "this" pointer. If the function returns a structure,
3215 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3216 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
3217 this_rtx = gen_rtx_REG (Pmode, (MB_ABI_FIRST_ARG_REGNUM + 1));
3218 else
3219 this_rtx = gen_rtx_REG (Pmode, MB_ABI_FIRST_ARG_REGNUM);
3220
3221 /* Apply the constant offset, if required. */
3222 if (delta)
3223 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
3224
3225 /* Apply the offset from the vtable, if required. */
3226 if (vcall_offset)
3227 {
3228 rtx vcall_offset_rtx = GEN_INT (vcall_offset);
3229 rtx temp1 = gen_rtx_REG (Pmode, MB_ABI_TEMP1_REGNUM);
3230
3231 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
3232
3233 rtx loc = gen_rtx_PLUS (Pmode, temp1, vcall_offset_rtx);
3234 emit_move_insn (temp1, gen_rtx_MEM (Pmode, loc));
3235
3236 emit_insn (gen_addsi3 (this_rtx, this_rtx, temp1));
3237 }
3238
3239 /* Generate a tail call to the target function. */
3240 if (!TREE_USED (function))
3241 {
3242 assemble_external (function);
3243 TREE_USED (function) = 1;
3244 }
3245
3246 funexp = XEXP (DECL_RTL (function), 0);
3247 rtx temp2 = gen_rtx_REG (Pmode, MB_ABI_TEMP2_REGNUM);
3248
3249 if (flag_pic)
3250 emit_move_insn (temp2, expand_pic_symbol_ref (Pmode, funexp));
3251 else
3252 emit_move_insn (temp2, funexp);
3253
3254 emit_insn (gen_indirect_jump (temp2));
3255
3256 /* Run just enough of rest_of_compilation. This sequence was
3257 "borrowed" from rs6000.c. */
3258 insn = get_insns ();
3259 shorten_branches (insn);
3260 final_start_function (insn, file, 1);
3261 final (insn, file, 1);
3262 final_end_function ();
3263
3264 reload_completed = 0;
3265 epilogue_completed = 0;
3266 }
3267
2621 bool 3268 bool
2622 microblaze_expand_move (enum machine_mode mode, rtx operands[]) 3269 microblaze_expand_move (machine_mode mode, rtx operands[])
2623 { 3270 {
3271 rtx op0, op1;
3272
3273 op0 = operands[0];
3274 op1 = operands[1];
3275
3276 if (!register_operand (op0, SImode)
3277 && !register_operand (op1, SImode)
3278 && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
3279 {
3280 rtx temp = force_reg (SImode, op1);
3281 emit_move_insn (op0, temp);
3282 return true;
3283 }
2624 /* If operands[1] is a constant address invalid for pic, then we need to 3284 /* If operands[1] is a constant address invalid for pic, then we need to
2625 handle it just like LEGITIMIZE_ADDRESS does. */ 3285 handle it just like LEGITIMIZE_ADDRESS does. */
2626 if (flag_pic) 3286 if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
2627 { 3287 {
2628 if (GET_CODE (operands[0]) == MEM) 3288 rtx result;
3289 if (microblaze_tls_symbol_p(op1))
2629 { 3290 {
2630 rtx addr = XEXP (operands[0], 0); 3291 result = microblaze_legitimize_tls_address (op1, NULL_RTX);
2631 if (GET_CODE (addr) == SYMBOL_REF) 3292 emit_move_insn (op0, result);
2632 { 3293 return true;
2633 rtx ptr_reg, result;
2634
2635 if (reload_in_progress)
2636 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2637
2638 addr = expand_pic_symbol_ref (mode, addr);
2639 ptr_reg = gen_reg_rtx (Pmode);
2640 emit_move_insn (ptr_reg, addr);
2641 result = gen_rtx_MEM (mode, ptr_reg);
2642 operands[0] = result;
2643 }
2644 } 3294 }
2645 if (GET_CODE (operands[1]) == SYMBOL_REF 3295 else if (flag_pic)
2646 || GET_CODE (operands[1]) == LABEL_REF)
2647 { 3296 {
2648 rtx result;
2649 if (reload_in_progress) 3297 if (reload_in_progress)
2650 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); 3298 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2651 result = expand_pic_symbol_ref (mode, operands[1]); 3299 result = expand_pic_symbol_ref (mode, op1);
2652 if (GET_CODE (operands[0]) != REG) 3300 emit_move_insn (op0, result);
2653 {
2654 rtx ptr_reg = gen_reg_rtx (Pmode);
2655 emit_move_insn (ptr_reg, result);
2656 emit_move_insn (operands[0], ptr_reg);
2657 }
2658 else
2659 {
2660 emit_move_insn (operands[0], result);
2661 }
2662 return true; 3301 return true;
2663 } 3302 }
2664 else if (GET_CODE (operands[1]) == MEM && 3303 }
2665 GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) 3304 /* Handle Case of (const (plus symbol const_int)). */
3305 if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
3306 {
3307 rtx p0, p1;
3308
3309 p0 = XEXP (XEXP (op1, 0), 0);
3310 p1 = XEXP (XEXP (op1, 0), 1);
3311
3312 if ((GET_CODE (p1) == CONST_INT)
3313 && ((GET_CODE (p0) == UNSPEC)
3314 || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3315 && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
3316 || !SMALL_INT (p1)))))
2666 { 3317 {
2667 rtx result; 3318 rtx temp = force_reg (SImode, p0);
2668 rtx ptr_reg; 3319 rtx temp2 = p1;
2669 if (reload_in_progress) 3320
3321 if (flag_pic && reload_in_progress)
2670 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); 3322 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2671 result = expand_pic_symbol_ref (mode, XEXP (operands[1], 0)); 3323 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
2672
2673 ptr_reg = gen_reg_rtx (Pmode);
2674
2675 emit_move_insn (ptr_reg, result);
2676 result = gen_rtx_MEM (mode, ptr_reg);
2677 emit_move_insn (operands[0], result);
2678 return true; 3324 return true;
2679 } 3325 }
2680 else if (pic_address_needs_scratch (operands[1]))
2681 {
2682 rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0));
2683 rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
2684
2685 if (reload_in_progress)
2686 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2687 emit_move_insn (operands[0], gen_rtx_PLUS (SImode, temp, temp2));
2688 return true;
2689 }
2690 }
2691
2692 if ((reload_in_progress | reload_completed) == 0
2693 && !register_operand (operands[0], SImode)
2694 && !register_operand (operands[1], SImode)
2695 && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
2696 {
2697 rtx temp = force_reg (SImode, operands[1]);
2698 emit_move_insn (operands[0], temp);
2699 return true;
2700 } 3326 }
2701 return false; 3327 return false;
2702 } 3328 }
2703 3329
2704 /* Expand shift operations. */ 3330 /* Expand shift operations. */
2721 || (GET_CODE (operands[0]) == SUBREG) 3347 || (GET_CODE (operands[0]) == SUBREG)
2722 || (GET_CODE (operands[1]) == REG) 3348 || (GET_CODE (operands[1]) == REG)
2723 || (GET_CODE (operands[1]) == SUBREG)); 3349 || (GET_CODE (operands[1]) == SUBREG));
2724 3350
2725 /* Shift by zero -- copy regs if necessary. */ 3351 /* Shift by zero -- copy regs if necessary. */
2726 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 0)) 3352 if (operands[2] == const0_rtx
2727 { 3353 && !rtx_equal_p (operands[0], operands[1]))
2728 if (REGNO (operands[0]) != REGNO (operands[1])) 3354 {
2729 emit_insn (gen_movsi (operands[0], operands[1])); 3355 emit_insn (gen_movsi (operands[0], operands[1]));
2730 return 1; 3356 return 1;
2731 } 3357 }
2732 3358
2733 return 0; 3359 return 0;
2734 } 3360 }
2739 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) 3365 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
2740 { 3366 {
2741 if (count != 0) 3367 if (count != 0)
2742 return NULL_RTX; 3368 return NULL_RTX;
2743 3369
2744 return gen_rtx_PLUS (Pmode, 3370 return get_hard_reg_initial_val (Pmode,
2745 get_hard_reg_initial_val (Pmode, 3371 MB_ABI_SUB_RETURN_ADDR_REGNUM);
2746 MB_ABI_SUB_RETURN_ADDR_REGNUM), 3372 }
2747 GEN_INT (8)); 3373
2748 } 3374 void
2749 3375 microblaze_eh_return (rtx op0)
2750 /* Put string into .sdata2 if below threashold. */ 3376 {
3377 emit_insn (gen_movsi (gen_rtx_MEM (Pmode, stack_pointer_rtx), op0));
3378 }
3379
3380 /* Queue an .ident string in the queue of top-level asm statements.
3381 If the string size is below the threshold, put it into .sdata2.
3382 If the front-end is done, we must be being called from toplev.c.
3383 In that case, do nothing. */
2751 void 3384 void
2752 microblaze_asm_output_ident (FILE *file ATTRIBUTE_UNUSED, const char *string) 3385 microblaze_asm_output_ident (const char *string)
2753 { 3386 {
2754 int size = strlen (string) + 1; 3387 const char *section_asm_op;
3388 int size;
3389 char *buf;
3390
3391 if (symtab->state != PARSING)
3392 return;
3393
3394 size = strlen (string) + 1;
2755 if (size <= microblaze_section_threshold) 3395 if (size <= microblaze_section_threshold)
2756 switch_to_section (sdata2_section); 3396 section_asm_op = SDATA2_SECTION_ASM_OP;
2757 else 3397 else
2758 switch_to_section (readonly_data_section); 3398 section_asm_op = READONLY_DATA_SECTION_ASM_OP;
2759 assemble_string (string, size); 3399
3400 buf = ACONCAT ((section_asm_op, "\n\t.ascii \"", string, "\\0\"\n", NULL));
3401 symtab->finalize_toplevel_asm (build_string (strlen (buf), buf));
2760 } 3402 }
2761 3403
2762 static void 3404 static void
2763 microblaze_elf_asm_init_sections (void) 3405 microblaze_elf_asm_init_sections (void)
2764 { 3406 {
2770 /* Generate assembler code for constant parts of a trampoline. */ 3412 /* Generate assembler code for constant parts of a trampoline. */
2771 3413
2772 static void 3414 static void
2773 microblaze_asm_trampoline_template (FILE *f) 3415 microblaze_asm_trampoline_template (FILE *f)
2774 { 3416 {
2775 fprintf (f, "\t.word\t0x03e00821\t\t# move $1,$31\n"); 3417 fprintf (f, "\tmfs r18, rpc\n");
2776 fprintf (f, "\t.word\t0x04110001\t\t# bgezal $0,.+8\n"); 3418 fprintf (f, "\tlwi r3, r18, 16\n");
2777 fprintf (f, "\t.word\t0x00000000\t\t# nop\n"); 3419 fprintf (f, "\tlwi r18, r18, 20\n");
2778 fprintf (f, "\t.word\t0x8fe30014\t\t# lw $3,20($31)\n"); 3420 fprintf (f, "\tbra r18\n");
2779 fprintf (f, "\t.word\t0x8fe20018\t\t# lw $2,24($31)\n");
2780 fprintf (f, "\t.word\t0x0060c821\t\t# move $25,$3 (abicalls)\n");
2781 fprintf (f, "\t.word\t0x00600008\t\t# jr $3\n");
2782 fprintf (f, "\t.word\t0x0020f821\t\t# move $31,$1\n");
2783 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */ 3421 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
2784 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */ 3422 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
2785 } 3423 }
2786 3424
2787 /* Implement TARGET_TRAMPOLINE_INIT. */ 3425 /* Implement TARGET_TRAMPOLINE_INIT. */
2791 { 3429 {
2792 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); 3430 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2793 rtx mem; 3431 rtx mem;
2794 3432
2795 emit_block_move (m_tramp, assemble_trampoline_template (), 3433 emit_block_move (m_tramp, assemble_trampoline_template (),
2796 GEN_INT (8*UNITS_PER_WORD), BLOCK_OP_NORMAL); 3434 GEN_INT (6*UNITS_PER_WORD), BLOCK_OP_NORMAL);
2797 3435
2798 mem = adjust_address (m_tramp, SImode, 8); 3436 mem = adjust_address (m_tramp, SImode, 16);
2799 emit_move_insn (mem, chain_value); 3437 emit_move_insn (mem, chain_value);
2800 mem = adjust_address (m_tramp, SImode, 12); 3438 mem = adjust_address (m_tramp, SImode, 20);
2801 emit_move_insn (mem, fnaddr); 3439 emit_move_insn (mem, fnaddr);
2802 } 3440 }
2803 3441
2804 /* Emit instruction to perform compare.
2805 cmp is (compare_op op0 op1). */
2806 static rtx
2807 microblaze_emit_compare (enum machine_mode mode, rtx cmp, enum rtx_code *cmp_code)
2808 {
2809 rtx cmp_op0 = XEXP (cmp, 0);
2810 rtx cmp_op1 = XEXP (cmp, 1);
2811 rtx comp_reg = gen_reg_rtx (SImode);
2812 enum rtx_code code = *cmp_code;
2813
2814 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
2815
2816 /* If comparing against zero, just test source reg. */
2817 if (cmp_op1 == const0_rtx)
2818 return cmp_op0;
2819
2820 if (code == EQ || code == NE)
2821 {
2822 if (TARGET_PATTERN_COMPARE && GET_CODE(cmp_op1) == REG)
2823 {
2824 if (code == EQ)
2825 emit_insn (gen_seq_internal_pat (comp_reg, cmp_op0, cmp_op1));
2826 else
2827 {
2828 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0, cmp_op1));
2829 *cmp_code = EQ;
2830 }
2831 }
2832 else
2833 /* Use xor for equal/not-equal comparison. */
2834 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
2835 }
2836 else if (code == GT || code == GTU || code == LE || code == LEU)
2837 {
2838 /* MicroBlaze compare is not symmetrical. */
2839 /* Swap argument order. */
2840 cmp_op1 = force_reg (mode, cmp_op1);
2841 if (code == GT || code == LE)
2842 emit_insn (gen_signed_compare (comp_reg, cmp_op0, cmp_op1));
2843 else
2844 emit_insn (gen_unsigned_compare (comp_reg, cmp_op0, cmp_op1));
2845 /* Translate test condition. */
2846 *cmp_code = swap_condition (code);
2847 }
2848 else /* if (code == GE || code == GEU || code == LT || code == LTU) */
2849 {
2850 cmp_op1 = force_reg (mode, cmp_op1);
2851 if (code == GE || code == LT)
2852 emit_insn (gen_signed_compare (comp_reg, cmp_op1, cmp_op0));
2853 else
2854 emit_insn (gen_unsigned_compare (comp_reg, cmp_op1, cmp_op0));
2855 }
2856
2857 return comp_reg;
2858 }
2859
2860 /* Generate conditional branch -- first, generate test condition, 3442 /* Generate conditional branch -- first, generate test condition,
2861 second, generate correct branch instruction. */ 3443 second, generate correct branch instruction. */
2862 3444
2863 void 3445 void
2864 microblaze_expand_conditional_branch (enum machine_mode mode, rtx operands[]) 3446 microblaze_expand_conditional_branch (machine_mode mode, rtx operands[])
2865 { 3447 {
2866 enum rtx_code code = GET_CODE (operands[0]); 3448 enum rtx_code code = GET_CODE (operands[0]);
2867 rtx comp; 3449 rtx cmp_op0 = operands[1];
3450 rtx cmp_op1 = operands[2];
3451 rtx label1 = operands[3];
3452 rtx comp_reg = gen_reg_rtx (SImode);
2868 rtx condition; 3453 rtx condition;
2869 3454
2870 comp = microblaze_emit_compare (mode, operands[0], &code); 3455 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
2871 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp, const0_rtx); 3456
2872 emit_jump_insn (gen_condjump (condition, operands[3])); 3457 /* If comparing against zero, just test source reg. */
3458 if (cmp_op1 == const0_rtx)
3459 {
3460 comp_reg = cmp_op0;
3461 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3462 emit_jump_insn (gen_condjump (condition, label1));
3463 }
3464
3465 else if (code == EQ || code == NE)
3466 {
3467 /* Use xor for equal/not-equal comparison. */
3468 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
3469 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3470 emit_jump_insn (gen_condjump (condition, label1));
3471 }
3472 else
3473 {
3474 /* Generate compare and branch in single instruction. */
3475 cmp_op1 = force_reg (mode, cmp_op1);
3476 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3477 emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1));
3478 }
3479 }
3480
3481 void
3482 microblaze_expand_conditional_branch_reg (machine_mode mode, rtx operands[])
3483 {
3484 enum rtx_code code = GET_CODE (operands[0]);
3485 rtx cmp_op0 = operands[1];
3486 rtx cmp_op1 = operands[2];
3487 rtx label1 = operands[3];
3488 rtx comp_reg = gen_reg_rtx (SImode);
3489 rtx condition;
3490
3491 gcc_assert ((GET_CODE (cmp_op0) == REG)
3492 || (GET_CODE (cmp_op0) == SUBREG));
3493
3494 /* If comparing against zero, just test source reg. */
3495 if (cmp_op1 == const0_rtx)
3496 {
3497 comp_reg = cmp_op0;
3498 condition = gen_rtx_fmt_ee (signed_condition (code),
3499 SImode, comp_reg, const0_rtx);
3500 emit_jump_insn (gen_condjump (condition, label1));
3501 }
3502 else if (code == EQ)
3503 {
3504 emit_insn (gen_seq_internal_pat (comp_reg,
3505 cmp_op0, cmp_op1));
3506 condition = gen_rtx_EQ (SImode, comp_reg, const0_rtx);
3507 emit_jump_insn (gen_condjump (condition, label1));
3508 }
3509 else if (code == NE)
3510 {
3511 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0,
3512 cmp_op1));
3513 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3514 emit_jump_insn (gen_condjump (condition, label1));
3515 }
3516 else
3517 {
3518 /* Generate compare and branch in single instruction. */
3519 cmp_op1 = force_reg (mode, cmp_op1);
3520 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3521 emit_jump_insn (gen_branch_compare (condition, cmp_op0,
3522 cmp_op1, label1));
3523 }
2873 } 3524 }
2874 3525
2875 void 3526 void
2876 microblaze_expand_conditional_branch_sf (rtx operands[]) 3527 microblaze_expand_conditional_branch_sf (rtx operands[])
2877 { 3528 {
2903 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */ 3554 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
2904 3555
2905 rtx regt1 = gen_reg_rtx (SImode); 3556 rtx regt1 = gen_reg_rtx (SImode);
2906 rtx reg18 = gen_rtx_REG (SImode, R_TMP); 3557 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
2907 rtx regqi = gen_reg_rtx (QImode); 3558 rtx regqi = gen_reg_rtx (QImode);
2908 rtx div_label = gen_label_rtx (); 3559 rtx_code_label *div_label = gen_label_rtx ();
2909 rtx div_end_label = gen_label_rtx (); 3560 rtx_code_label *div_end_label = gen_label_rtx ();
2910 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table"); 3561 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
2911 rtx mem_rtx; 3562 rtx mem_rtx;
2912 rtx ret; 3563 rtx ret;
2913 rtx jump, cjump, insn; 3564 rtx_insn *jump, *cjump, *insn;
2914 3565
2915 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2])); 3566 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
2916 cjump = emit_jump_insn_after (gen_cbranchsi4 ( 3567 cjump = emit_jump_insn_after (gen_cbranchsi4 (
2917 gen_rtx_GTU (SImode, regt1, GEN_INT (15)), 3568 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
2918 regt1, GEN_INT (15), div_label), insn); 3569 regt1, GEN_INT (15), div_label), insn);
2932 LABEL_NUSES (div_end_label) = 1; 3583 LABEL_NUSES (div_end_label) = 1;
2933 emit_barrier (); 3584 emit_barrier ();
2934 3585
2935 emit_label (div_label); 3586 emit_label (div_label);
2936 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"), 3587 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
2937 operands[0], LCT_NORMAL, 3588 operands[0], LCT_NORMAL,
2938 GET_MODE (operands[0]), 2, operands[1], 3589 GET_MODE (operands[0]),
2939 GET_MODE (operands[1]), operands[2], 3590 operands[1], GET_MODE (operands[1]),
2940 GET_MODE (operands[2])); 3591 operands[2], GET_MODE (operands[2]));
2941 if (ret != operands[0]) 3592 if (ret != operands[0])
2942 emit_move_insn (operands[0], ret); 3593 emit_move_insn (operands[0], ret);
2943 3594
2944 emit_label (div_end_label); 3595 emit_label (div_end_label);
2945 emit_insn (gen_blockage ()); 3596 emit_insn (gen_blockage ());
2954 return LIBCALL_VALUE (TYPE_MODE (valtype)); 3605 return LIBCALL_VALUE (TYPE_MODE (valtype));
2955 } 3606 }
2956 3607
2957 /* Implement TARGET_SCHED_ADJUST_COST. */ 3608 /* Implement TARGET_SCHED_ADJUST_COST. */
2958 static int 3609 static int
2959 microblaze_adjust_cost (rtx insn ATTRIBUTE_UNUSED, rtx link, 3610 microblaze_adjust_cost (rtx_insn *, int dep_type, rtx_insn *, int cost,
2960 rtx dep ATTRIBUTE_UNUSED, int cost) 3611 unsigned int)
2961 { 3612 {
2962 if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT) 3613 if (dep_type == REG_DEP_OUTPUT || dep_type == 0)
2963 return cost; 3614 return cost;
2964 if (REG_NOTE_KIND (link) != 0) 3615 return 0;
2965 return 0; 3616 }
2966 return cost; 3617
3618 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3619
3620 At present, GAS doesn't understand li.[sd], so don't allow it
3621 to be generated at present. */
3622 static bool
3623 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
3624 {
3625
3626 if (microblaze_cannot_force_const_mem(mode, x))
3627 return false;
3628
3629 if (GET_CODE (x) == CONST_DOUBLE)
3630 {
3631 return microblaze_const_double_ok (x, GET_MODE (x));
3632 }
3633
3634 /* Handle Case of (const (plus unspec const_int)). */
3635 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
3636 {
3637 rtx p0, p1;
3638
3639 p0 = XEXP (XEXP (x, 0), 0);
3640 p1 = XEXP (XEXP (x, 0), 1);
3641
3642 if (GET_CODE(p1) == CONST_INT)
3643 {
3644 /* Const offset from UNSPEC is not supported. */
3645 if ((GET_CODE (p0) == UNSPEC))
3646 return false;
3647
3648 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3649 && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
3650 return false;
3651 }
3652 }
3653
3654 return true;
3655 }
3656
3657 static rtx
3658 get_branch_target (rtx branch)
3659 {
3660 if (CALL_P (branch))
3661 {
3662 rtx call;
3663
3664 call = XVECEXP (PATTERN (branch), 0, 0);
3665 if (GET_CODE (call) == SET)
3666 call = SET_SRC (call);
3667 if (GET_CODE (call) != CALL)
3668 abort ();
3669 return XEXP (XEXP (call, 0), 0);
3670 }
3671
3672 return NULL_RTX;
3673 }
3674
3675 /* Heuristics to identify where to insert at the
3676 fall through path of the caller function. If there
3677 is a call after the caller branch delay slot then
3678 we dont generate the instruction prefetch instruction.
3679
3680 Scan up to 32 instructions after the call and checks
3681 for the JUMP and call instruction . If there is a call
3682 or JUMP instruction in the range of 32 instruction "wic"
3683 instruction wont be generated. Otherwise insert the "wic"
3684 instruction in the fall through of the call instruction
3685 four instruction after the call. before_4 is used for
3686 the position to insert "wic" instructions. before_16 is
3687 used to check for call and JUMP instruction for first
3688 15 insns. */
3689
3690 static void
3691 insert_wic_for_ilb_runout (rtx_insn *first)
3692 {
3693 rtx_insn *insn;
3694 rtx_insn *before_4 = 0;
3695 rtx_insn *before_16 = 0;
3696 int addr_offset = 0;
3697 int length;
3698 int wic_addr0 = 128 * 4;
3699
3700 int first_addr = INSN_ADDRESSES (INSN_UID (first));
3701
3702 for (insn = first; insn; insn = NEXT_INSN (insn))
3703 if (INSN_P (insn))
3704 {
3705 addr_offset = INSN_ADDRESSES (INSN_UID (insn)) - first_addr;
3706 length = get_attr_length (insn);
3707 if (before_4 == 0 && addr_offset + length >= 4 * 4)
3708 before_4 = insn;
3709
3710 if (JUMP_P(insn))
3711 return;
3712 if (before_16 == 0 && addr_offset + length >= 14 * 4)
3713 before_16 = insn;
3714 if (CALL_P (insn) || tablejump_p (insn, 0, 0))
3715 return;
3716 if (addr_offset + length >= 32 * 4)
3717 {
3718 gcc_assert (before_4 && before_16);
3719 if (wic_addr0 > 4 * 4)
3720 {
3721 insn =
3722 emit_insn_before (gen_iprefetch
3723 (gen_int_mode (addr_offset, SImode)),
3724 before_4);
3725 recog_memoized (insn);
3726 INSN_LOCATION (insn) = INSN_LOCATION (before_4);
3727 INSN_ADDRESSES_NEW (insn, INSN_ADDRESSES (INSN_UID (before_4)));
3728 return;
3729 }
3730 }
3731 }
3732 }
3733
3734 /* Insert instruction prefetch instruction at the fall
3735 through path of the function call. */
3736
3737 static void
3738 insert_wic (void)
3739 {
3740 rtx_insn *insn;
3741 int i;
3742 basic_block bb, prev = 0;
3743 rtx branch_target = 0;
3744
3745 shorten_branches (get_insns ());
3746
3747 for (i = 0; i < n_basic_blocks_for_fn (cfun) - 1; i++)
3748 {
3749 edge e;
3750 edge_iterator ei;
3751 bool simple_loop = false;
3752
3753 bb = BASIC_BLOCK_FOR_FN (cfun, i);
3754
3755 if (bb == NULL)
3756 continue;
3757
3758 if ((prev != 0) && (prev != bb))
3759 continue;
3760 else
3761 prev = 0;
3762
3763 FOR_EACH_EDGE (e, ei, bb->preds)
3764 if (e->src == bb)
3765 {
3766 simple_loop = true;
3767 prev= e->dest;
3768 break;
3769 }
3770
3771 for (insn = BB_END (bb); insn; insn = PREV_INSN (insn))
3772 {
3773 if (INSN_P (insn) && !simple_loop
3774 && CALL_P(insn))
3775 {
3776 if ((branch_target = get_branch_target (insn)))
3777 insert_wic_for_ilb_runout (
3778 next_active_insn (next_active_insn (insn)));
3779 }
3780 if (insn == BB_HEAD (bb))
3781 break;
3782 }
3783 }
3784 }
3785
3786 /* The reorg function defined through the macro
3787 TARGET_MACHINE_DEPENDENT_REORG. */
3788
3789 static void
3790 microblaze_machine_dependent_reorg (void)
3791 {
3792 if (TARGET_PREFETCH)
3793 {
3794 compute_bb_for_insn ();
3795 loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
3796 shorten_branches (get_insns ());
3797 insert_wic ();
3798 loop_optimizer_finalize ();
3799 free_bb_for_insn ();
3800 return;
3801 }
3802 }
3803
3804 /* Implement TARGET_CONSTANT_ALIGNMENT. */
3805
3806 static HOST_WIDE_INT
3807 microblaze_constant_alignment (const_tree exp, HOST_WIDE_INT align)
3808 {
3809 if (TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR)
3810 return MAX (align, BITS_PER_WORD);
3811 return align;
3812 }
3813
3814 /* Implement TARGET_STARTING_FRAME_OFFSET. */
3815
3816 static HOST_WIDE_INT
3817 microblaze_starting_frame_offset (void)
3818 {
3819 return (crtl->outgoing_args_size + FIRST_PARM_OFFSET(FNDECL));
2967 } 3820 }
2968 3821
2969 #undef TARGET_ENCODE_SECTION_INFO 3822 #undef TARGET_ENCODE_SECTION_INFO
2970 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info 3823 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
2971 3824
2979 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue 3832 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
2980 3833
2981 #undef TARGET_RTX_COSTS 3834 #undef TARGET_RTX_COSTS
2982 #define TARGET_RTX_COSTS microblaze_rtx_costs 3835 #define TARGET_RTX_COSTS microblaze_rtx_costs
2983 3836
3837 #undef TARGET_CANNOT_FORCE_CONST_MEM
3838 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3839
2984 #undef TARGET_ADDRESS_COST 3840 #undef TARGET_ADDRESS_COST
2985 #define TARGET_ADDRESS_COST microblaze_address_cost 3841 #define TARGET_ADDRESS_COST microblaze_address_cost
2986 3842
2987 #undef TARGET_ATTRIBUTE_TABLE 3843 #undef TARGET_ATTRIBUTE_TABLE
2988 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table 3844 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
2998 3854
2999 #undef TARGET_ASM_FUNCTION_END_PROLOGUE 3855 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3000 #define TARGET_ASM_FUNCTION_END_PROLOGUE \ 3856 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3001 microblaze_function_end_prologue 3857 microblaze_function_end_prologue
3002 3858
3003 #undef TARGET_HANDLE_OPTION
3004 #define TARGET_HANDLE_OPTION microblaze_handle_option
3005
3006 #undef TARGET_DEFAULT_TARGET_FLAGS
3007 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
3008
3009 #undef TARGET_ARG_PARTIAL_BYTES 3859 #undef TARGET_ARG_PARTIAL_BYTES
3010 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes 3860 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3011 3861
3012 #undef TARGET_FUNCTION_ARG 3862 #undef TARGET_FUNCTION_ARG
3013 #define TARGET_FUNCTION_ARG microblaze_function_arg 3863 #define TARGET_FUNCTION_ARG microblaze_function_arg
3022 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address 3872 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3023 3873
3024 #undef TARGET_LEGITIMATE_ADDRESS_P 3874 #undef TARGET_LEGITIMATE_ADDRESS_P
3025 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p 3875 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3026 3876
3877 #undef TARGET_LRA_P
3878 #define TARGET_LRA_P hook_bool_void_false
3879
3027 #undef TARGET_FRAME_POINTER_REQUIRED 3880 #undef TARGET_FRAME_POINTER_REQUIRED
3028 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required 3881 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3029 3882
3030 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE 3883 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3031 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template 3884 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3040 #define TARGET_FUNCTION_VALUE microblaze_function_value 3893 #define TARGET_FUNCTION_VALUE microblaze_function_value
3041 3894
3042 #undef TARGET_SECONDARY_RELOAD 3895 #undef TARGET_SECONDARY_RELOAD
3043 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload 3896 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3044 3897
3898 #undef TARGET_ASM_OUTPUT_MI_THUNK
3899 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3900
3901 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3902 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3903
3045 #undef TARGET_SCHED_ADJUST_COST 3904 #undef TARGET_SCHED_ADJUST_COST
3046 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost 3905 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3047 3906
3048 #undef TARGET_ASM_INIT_SECTIONS 3907 #undef TARGET_ASM_INIT_SECTIONS
3049 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections 3908 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3050 3909
3051 #undef TARGET_OPTION_OVERRIDE 3910 #undef TARGET_OPTION_OVERRIDE
3052 #define TARGET_OPTION_OVERRIDE microblaze_option_override 3911 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3053 3912
3054 #undef TARGET_OPTION_OPTIMIZATION_TABLE 3913 #undef TARGET_LEGITIMATE_CONSTANT_P
3055 #define TARGET_OPTION_OPTIMIZATION_TABLE microblaze_option_optimization_table 3914 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3056 3915
3057 #undef TARGET_EXCEPT_UNWIND_INFO 3916 #undef TARGET_MACHINE_DEPENDENT_REORG
3058 #define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info 3917 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg
3918
3919 #undef TARGET_HARD_REGNO_MODE_OK
3920 #define TARGET_HARD_REGNO_MODE_OK microblaze_hard_regno_mode_ok
3921
3922 #undef TARGET_MODES_TIEABLE_P
3923 #define TARGET_MODES_TIEABLE_P microblaze_modes_tieable_p
3924
3925 #undef TARGET_CONSTANT_ALIGNMENT
3926 #define TARGET_CONSTANT_ALIGNMENT microblaze_constant_alignment
3927
3928 #undef TARGET_STARTING_FRAME_OFFSET
3929 #define TARGET_STARTING_FRAME_OFFSET microblaze_starting_frame_offset
3059 3930
3060 struct gcc_target targetm = TARGET_INITIALIZER; 3931 struct gcc_target targetm = TARGET_INITIALIZER;
3061 3932
3062 #include "gt-microblaze.h" 3933 #include "gt-microblaze.h"