Mercurial > hg > CbC > CbC_gcc
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" |