1 /* Target machine subroutines for Altera Nios II.
2 Copyright (C) 2012-2015 Free Software Foundation, Inc.
3 Contributed by Jonah Graham (jgraham@altera.com),
4 Will Reece (wreece@altera.com), and Jeff DaSilva (jdasilva@altera.com).
5 Contributed by Mentor Graphics, Inc.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published
11 by the Free Software Foundation; either version 3, or (at your
12 option) any later version.
14 GCC is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
17 License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3. If not see
21 <http://www.gnu.org/licenses/>. */
25 #include "coretypes.h"
31 #include "fold-const.h"
33 #include "hard-reg-set.h"
34 #include "insn-config.h"
35 #include "conditions.h"
37 #include "insn-attr.h"
49 #include "insn-codes.h"
52 #include "dominance.h"
58 #include "cfgcleanup.h"
59 #include "basic-block.h"
60 #include "diagnostic-core.h"
64 #include "langhooks.h"
68 #include "stor-layout.h"
71 /* This file should be included last. */
72 #include "target-def.h"
74 /* Forward function declarations. */
75 static bool prologue_saved_reg_p (unsigned);
76 static void nios2_load_pic_register (void);
77 static void nios2_register_custom_code (unsigned int, enum nios2_ccs_code
, int);
78 static const char *nios2_unspec_reloc_name (int);
79 static void nios2_register_builtin_fndecl (unsigned, tree
);
81 /* Threshold for data being put into the small data/bss area, instead
82 of the normal data area (references to the small data/bss area take
83 1 instruction, and use the global pointer, references to the normal
84 data area takes 2 instructions). */
85 unsigned HOST_WIDE_INT nios2_section_threshold
= NIOS2_DEFAULT_GVALUE
;
87 struct GTY (()) machine_function
89 /* Current frame information, to be filled in by nios2_compute_frame_layout
90 with register save masks, and offsets for the current function. */
92 /* Mask of registers to save. */
93 unsigned int save_mask
;
94 /* Number of bytes that the entire frame takes up. */
96 /* Number of bytes that variables take up. */
98 /* Number of bytes that outgoing arguments take up. */
100 /* Number of bytes needed to store registers in frame. */
102 /* Offset from new stack pointer to store registers. */
103 int save_regs_offset
;
104 /* Offset from save_regs_offset to store frame pointer register. */
106 /* != 0 if frame layout already calculated. */
110 /* State to track the assignment of custom codes to FPU/custom builtins. */
111 static enum nios2_ccs_code custom_code_status
[256];
112 static int custom_code_index
[256];
113 /* Set to true if any conflicts (re-use of a code between 0-255) are found. */
114 static bool custom_code_conflict
= false;
117 /* Definition of builtin function types for nios2. */
121 N2_FTYPE(1, (VOID)) \
122 N2_FTYPE(2, (DF, DF)) \
123 N2_FTYPE(3, (DF, DF, DF)) \
124 N2_FTYPE(2, (DF, SF)) \
125 N2_FTYPE(2, (DF, SI)) \
126 N2_FTYPE(2, (DF, UI)) \
127 N2_FTYPE(2, (SF, DF)) \
128 N2_FTYPE(2, (SF, SF)) \
129 N2_FTYPE(3, (SF, SF, SF)) \
130 N2_FTYPE(2, (SF, SI)) \
131 N2_FTYPE(2, (SF, UI)) \
132 N2_FTYPE(2, (SI, CVPTR)) \
133 N2_FTYPE(2, (SI, DF)) \
134 N2_FTYPE(3, (SI, DF, DF)) \
135 N2_FTYPE(2, (SI, SF)) \
136 N2_FTYPE(3, (SI, SF, SF)) \
137 N2_FTYPE(2, (SI, SI)) \
138 N2_FTYPE(2, (UI, CVPTR)) \
139 N2_FTYPE(2, (UI, DF)) \
140 N2_FTYPE(2, (UI, SF)) \
141 N2_FTYPE(2, (VOID, DF)) \
142 N2_FTYPE(2, (VOID, SF)) \
143 N2_FTYPE(3, (VOID, SI, SI)) \
144 N2_FTYPE(3, (VOID, VPTR, SI))
146 #define N2_FTYPE_OP1(R) N2_FTYPE_ ## R ## _VOID
147 #define N2_FTYPE_OP2(R, A1) N2_FTYPE_ ## R ## _ ## A1
148 #define N2_FTYPE_OP3(R, A1, A2) N2_FTYPE_ ## R ## _ ## A1 ## _ ## A2
150 /* Expand ftcode enumeration. */
152 #define N2_FTYPE(N,ARGS) N2_FTYPE_OP ## N ARGS,
158 /* Return the tree function type, based on the ftcode. */
160 nios2_ftype (enum nios2_ftcode ftcode
)
162 static tree types
[(int) N2_FTYPE_MAX
];
164 tree N2_TYPE_SF
= float_type_node
;
165 tree N2_TYPE_DF
= double_type_node
;
166 tree N2_TYPE_SI
= integer_type_node
;
167 tree N2_TYPE_UI
= unsigned_type_node
;
168 tree N2_TYPE_VOID
= void_type_node
;
170 static const_tree N2_TYPE_CVPTR
, N2_TYPE_VPTR
;
173 /* const volatile void *. */
175 = build_pointer_type (build_qualified_type (void_type_node
,
177 | TYPE_QUAL_VOLATILE
)));
178 /* volatile void *. */
180 = build_pointer_type (build_qualified_type (void_type_node
,
181 TYPE_QUAL_VOLATILE
));
183 if (types
[(int) ftcode
] == NULL_TREE
)
186 #define N2_FTYPE_ARGS1(R) N2_TYPE_ ## R
187 #define N2_FTYPE_ARGS2(R,A1) N2_TYPE_ ## R, N2_TYPE_ ## A1
188 #define N2_FTYPE_ARGS3(R,A1,A2) N2_TYPE_ ## R, N2_TYPE_ ## A1, N2_TYPE_ ## A2
189 #define N2_FTYPE(N,ARGS) \
190 case N2_FTYPE_OP ## N ARGS: \
191 types[(int) ftcode] \
192 = build_function_type_list (N2_FTYPE_ARGS ## N ARGS, NULL_TREE); \
196 default: gcc_unreachable ();
198 return types
[(int) ftcode
];
202 /* Definition of FPU instruction descriptions. */
204 struct nios2_fpu_insn_info
207 int num_operands
, *optvar
;
210 #define N2F_DFREQ 0x2
211 #define N2F_UNSAFE 0x4
212 #define N2F_FINITE 0x8
213 #define N2F_NO_ERRNO 0x10
215 enum insn_code icode
;
216 enum nios2_ftcode ftcode
;
219 /* Base macro for defining FPU instructions. */
220 #define N2FPU_INSN_DEF_BASE(insn, nop, flags, icode, args) \
221 { #insn, nop, &nios2_custom_ ## insn, OPT_mcustom_##insn##_, \
222 OPT_mno_custom_##insn, flags, CODE_FOR_ ## icode, \
223 N2_FTYPE_OP ## nop args }
225 /* Arithmetic and math functions; 2 or 3 operand FP operations. */
226 #define N2FPU_OP2(mode) (mode, mode)
227 #define N2FPU_OP3(mode) (mode, mode, mode)
228 #define N2FPU_INSN_DEF(code, icode, nop, flags, m, M) \
229 N2FPU_INSN_DEF_BASE (f ## code ## m, nop, flags, \
230 icode ## m ## f ## nop, N2FPU_OP ## nop (M ## F))
231 #define N2FPU_INSN_SF(code, nop, flags) \
232 N2FPU_INSN_DEF (code, code, nop, flags, s, S)
233 #define N2FPU_INSN_DF(code, nop, flags) \
234 N2FPU_INSN_DEF (code, code, nop, flags | N2F_DF, d, D)
236 /* Compare instructions, 3 operand FP operation with a SI result. */
237 #define N2FPU_CMP_DEF(code, flags, m, M) \
238 N2FPU_INSN_DEF_BASE (fcmp ## code ## m, 3, flags, \
239 nios2_s ## code ## m ## f, (SI, M ## F, M ## F))
240 #define N2FPU_CMP_SF(code) N2FPU_CMP_DEF (code, 0, s, S)
241 #define N2FPU_CMP_DF(code) N2FPU_CMP_DEF (code, N2F_DF, d, D)
243 /* The order of definition needs to be maintained consistent with
244 enum n2fpu_code in nios2-opts.h. */
245 struct nios2_fpu_insn_info nios2_fpu_insn
[] =
247 /* Single precision instructions. */
248 N2FPU_INSN_SF (add
, 3, 0),
249 N2FPU_INSN_SF (sub
, 3, 0),
250 N2FPU_INSN_SF (mul
, 3, 0),
251 N2FPU_INSN_SF (div
, 3, 0),
252 /* Due to textual difference between min/max and smin/smax. */
253 N2FPU_INSN_DEF (min
, smin
, 3, N2F_FINITE
, s
, S
),
254 N2FPU_INSN_DEF (max
, smax
, 3, N2F_FINITE
, s
, S
),
255 N2FPU_INSN_SF (neg
, 2, 0),
256 N2FPU_INSN_SF (abs
, 2, 0),
257 N2FPU_INSN_SF (sqrt
, 2, 0),
258 N2FPU_INSN_SF (sin
, 2, N2F_UNSAFE
),
259 N2FPU_INSN_SF (cos
, 2, N2F_UNSAFE
),
260 N2FPU_INSN_SF (tan
, 2, N2F_UNSAFE
),
261 N2FPU_INSN_SF (atan
, 2, N2F_UNSAFE
),
262 N2FPU_INSN_SF (exp
, 2, N2F_UNSAFE
),
263 N2FPU_INSN_SF (log
, 2, N2F_UNSAFE
),
264 /* Single precision compares. */
265 N2FPU_CMP_SF (eq
), N2FPU_CMP_SF (ne
),
266 N2FPU_CMP_SF (lt
), N2FPU_CMP_SF (le
),
267 N2FPU_CMP_SF (gt
), N2FPU_CMP_SF (ge
),
269 /* Double precision instructions. */
270 N2FPU_INSN_DF (add
, 3, 0),
271 N2FPU_INSN_DF (sub
, 3, 0),
272 N2FPU_INSN_DF (mul
, 3, 0),
273 N2FPU_INSN_DF (div
, 3, 0),
274 /* Due to textual difference between min/max and smin/smax. */
275 N2FPU_INSN_DEF (min
, smin
, 3, N2F_FINITE
, d
, D
),
276 N2FPU_INSN_DEF (max
, smax
, 3, N2F_FINITE
, d
, D
),
277 N2FPU_INSN_DF (neg
, 2, 0),
278 N2FPU_INSN_DF (abs
, 2, 0),
279 N2FPU_INSN_DF (sqrt
, 2, 0),
280 N2FPU_INSN_DF (sin
, 2, N2F_UNSAFE
),
281 N2FPU_INSN_DF (cos
, 2, N2F_UNSAFE
),
282 N2FPU_INSN_DF (tan
, 2, N2F_UNSAFE
),
283 N2FPU_INSN_DF (atan
, 2, N2F_UNSAFE
),
284 N2FPU_INSN_DF (exp
, 2, N2F_UNSAFE
),
285 N2FPU_INSN_DF (log
, 2, N2F_UNSAFE
),
286 /* Double precision compares. */
287 N2FPU_CMP_DF (eq
), N2FPU_CMP_DF (ne
),
288 N2FPU_CMP_DF (lt
), N2FPU_CMP_DF (le
),
289 N2FPU_CMP_DF (gt
), N2FPU_CMP_DF (ge
),
291 /* Conversion instructions. */
292 N2FPU_INSN_DEF_BASE (floatis
, 2, 0, floatsisf2
, (SF
, SI
)),
293 N2FPU_INSN_DEF_BASE (floatus
, 2, 0, floatunssisf2
, (SF
, UI
)),
294 N2FPU_INSN_DEF_BASE (floatid
, 2, 0, floatsidf2
, (DF
, SI
)),
295 N2FPU_INSN_DEF_BASE (floatud
, 2, 0, floatunssidf2
, (DF
, UI
)),
296 N2FPU_INSN_DEF_BASE (round
, 2, N2F_NO_ERRNO
, lroundsfsi2
, (SI
, SF
)),
297 N2FPU_INSN_DEF_BASE (fixsi
, 2, 0, fix_truncsfsi2
, (SI
, SF
)),
298 N2FPU_INSN_DEF_BASE (fixsu
, 2, 0, fixuns_truncsfsi2
, (UI
, SF
)),
299 N2FPU_INSN_DEF_BASE (fixdi
, 2, 0, fix_truncdfsi2
, (SI
, DF
)),
300 N2FPU_INSN_DEF_BASE (fixdu
, 2, 0, fixuns_truncdfsi2
, (UI
, DF
)),
301 N2FPU_INSN_DEF_BASE (fextsd
, 2, 0, extendsfdf2
, (DF
, SF
)),
302 N2FPU_INSN_DEF_BASE (ftruncds
, 2, 0, truncdfsf2
, (SF
, DF
)),
304 /* X, Y access instructions. */
305 N2FPU_INSN_DEF_BASE (fwrx
, 2, N2F_DFREQ
, nios2_fwrx
, (VOID
, DF
)),
306 N2FPU_INSN_DEF_BASE (fwry
, 2, N2F_DFREQ
, nios2_fwry
, (VOID
, SF
)),
307 N2FPU_INSN_DEF_BASE (frdxlo
, 1, N2F_DFREQ
, nios2_frdxlo
, (SF
)),
308 N2FPU_INSN_DEF_BASE (frdxhi
, 1, N2F_DFREQ
, nios2_frdxhi
, (SF
)),
309 N2FPU_INSN_DEF_BASE (frdy
, 1, N2F_DFREQ
, nios2_frdy
, (SF
))
312 /* Some macros for ease of access. */
313 #define N2FPU(code) nios2_fpu_insn[(int) code]
314 #define N2FPU_ENABLED_P(code) (N2FPU_N(code) >= 0)
315 #define N2FPU_N(code) (*N2FPU(code).optvar)
316 #define N2FPU_NAME(code) (N2FPU(code).name)
317 #define N2FPU_ICODE(code) (N2FPU(code).icode)
318 #define N2FPU_FTCODE(code) (N2FPU(code).ftcode)
319 #define N2FPU_FINITE_P(code) (N2FPU(code).flags & N2F_FINITE)
320 #define N2FPU_UNSAFE_P(code) (N2FPU(code).flags & N2F_UNSAFE)
321 #define N2FPU_NO_ERRNO_P(code) (N2FPU(code).flags & N2F_NO_ERRNO)
322 #define N2FPU_DOUBLE_P(code) (N2FPU(code).flags & N2F_DF)
323 #define N2FPU_DOUBLE_REQUIRED_P(code) (N2FPU(code).flags & N2F_DFREQ)
325 /* Same as above, but for cases where using only the op part is shorter. */
326 #define N2FPU_OP(op) N2FPU(n2fpu_ ## op)
327 #define N2FPU_OP_NAME(op) N2FPU_NAME(n2fpu_ ## op)
328 #define N2FPU_OP_ENABLED_P(op) N2FPU_ENABLED_P(n2fpu_ ## op)
330 /* Export the FPU insn enabled predicate to nios2.md. */
332 nios2_fpu_insn_enabled (enum n2fpu_code code
)
334 return N2FPU_ENABLED_P (code
);
337 /* Return true if COND comparison for mode MODE is enabled under current
341 nios2_fpu_compare_enabled (enum rtx_code cond
, machine_mode mode
)
346 case EQ
: return N2FPU_OP_ENABLED_P (fcmpeqs
);
347 case NE
: return N2FPU_OP_ENABLED_P (fcmpnes
);
348 case GT
: return N2FPU_OP_ENABLED_P (fcmpgts
);
349 case GE
: return N2FPU_OP_ENABLED_P (fcmpges
);
350 case LT
: return N2FPU_OP_ENABLED_P (fcmplts
);
351 case LE
: return N2FPU_OP_ENABLED_P (fcmples
);
354 else if (mode
== DFmode
)
357 case EQ
: return N2FPU_OP_ENABLED_P (fcmpeqd
);
358 case NE
: return N2FPU_OP_ENABLED_P (fcmpned
);
359 case GT
: return N2FPU_OP_ENABLED_P (fcmpgtd
);
360 case GE
: return N2FPU_OP_ENABLED_P (fcmpged
);
361 case LT
: return N2FPU_OP_ENABLED_P (fcmpltd
);
362 case LE
: return N2FPU_OP_ENABLED_P (fcmpled
);
368 /* Stack layout and calling conventions. */
370 #define NIOS2_STACK_ALIGN(LOC) \
371 (((LOC) + ((PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) - 1)) \
372 & ~((PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) - 1))
374 /* Return the bytes needed to compute the frame pointer from the current
377 nios2_compute_frame_layout (void)
380 unsigned int save_mask
= 0;
386 if (cfun
->machine
->initialized
)
387 return cfun
->machine
->total_size
;
389 var_size
= NIOS2_STACK_ALIGN (get_frame_size ());
390 out_args_size
= NIOS2_STACK_ALIGN (crtl
->outgoing_args_size
);
391 total_size
= var_size
+ out_args_size
;
393 /* Calculate space needed for gp registers. */
395 for (regno
= 0; regno
<= LAST_GP_REG
; regno
++)
396 if (prologue_saved_reg_p (regno
))
398 save_mask
|= 1 << regno
;
402 /* If we call eh_return, we need to save the EH data registers. */
403 if (crtl
->calls_eh_return
)
408 for (i
= 0; (r
= EH_RETURN_DATA_REGNO (i
)) != INVALID_REGNUM
; i
++)
409 if (!(save_mask
& (1 << r
)))
416 cfun
->machine
->fp_save_offset
= 0;
417 if (save_mask
& (1 << HARD_FRAME_POINTER_REGNUM
))
419 int fp_save_offset
= 0;
420 for (regno
= 0; regno
< HARD_FRAME_POINTER_REGNUM
; regno
++)
421 if (save_mask
& (1 << regno
))
424 cfun
->machine
->fp_save_offset
= fp_save_offset
;
427 save_reg_size
= NIOS2_STACK_ALIGN (save_reg_size
);
428 total_size
+= save_reg_size
;
429 total_size
+= NIOS2_STACK_ALIGN (crtl
->args
.pretend_args_size
);
431 /* Save other computed information. */
432 cfun
->machine
->save_mask
= save_mask
;
433 cfun
->machine
->total_size
= total_size
;
434 cfun
->machine
->var_size
= var_size
;
435 cfun
->machine
->args_size
= out_args_size
;
436 cfun
->machine
->save_reg_size
= save_reg_size
;
437 cfun
->machine
->initialized
= reload_completed
;
438 cfun
->machine
->save_regs_offset
= out_args_size
+ var_size
;
443 /* Generate save/restore of register REGNO at SP + OFFSET. Used by the
444 prologue/epilogue expand routines. */
446 save_reg (int regno
, unsigned offset
)
448 rtx reg
= gen_rtx_REG (SImode
, regno
);
449 rtx addr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
450 gen_int_mode (offset
, Pmode
));
451 rtx insn
= emit_move_insn (gen_frame_mem (Pmode
, addr
), reg
);
452 RTX_FRAME_RELATED_P (insn
) = 1;
456 restore_reg (int regno
, unsigned offset
)
458 rtx reg
= gen_rtx_REG (SImode
, regno
);
459 rtx addr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
460 gen_int_mode (offset
, Pmode
));
461 rtx insn
= emit_move_insn (reg
, gen_frame_mem (Pmode
, addr
));
462 /* Tag epilogue unwind note. */
463 add_reg_note (insn
, REG_CFA_RESTORE
, reg
);
464 RTX_FRAME_RELATED_P (insn
) = 1;
467 /* Emit conditional trap for checking stack limit. */
469 nios2_emit_stack_limit_check (void)
471 if (REG_P (stack_limit_rtx
))
472 emit_insn (gen_ctrapsi4 (gen_rtx_LTU (VOIDmode
, stack_pointer_rtx
,
474 stack_pointer_rtx
, stack_limit_rtx
, GEN_INT (3)));
476 sorry ("only register based stack limit is supported");
479 /* Temp regno used inside prologue/epilogue. */
480 #define TEMP_REG_NUM 8
483 nios2_emit_add_constant (rtx reg
, HOST_WIDE_INT immed
)
486 if (SMALL_INT (immed
))
487 insn
= emit_insn (gen_add2_insn (reg
, gen_int_mode (immed
, Pmode
)));
490 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
491 emit_move_insn (tmp
, gen_int_mode (immed
, Pmode
));
492 insn
= emit_insn (gen_add2_insn (reg
, tmp
));
498 nios2_expand_prologue (void)
501 int total_frame_size
, save_offset
;
502 int sp_offset
; /* offset from base_reg to final stack value. */
503 int save_regs_base
; /* offset from base_reg to register save area. */
506 total_frame_size
= nios2_compute_frame_layout ();
508 if (flag_stack_usage_info
)
509 current_function_static_stack_size
= total_frame_size
;
511 /* Decrement the stack pointer. */
512 if (!SMALL_INT (total_frame_size
))
514 /* We need an intermediary point, this will point at the spill block. */
516 (gen_add2_insn (stack_pointer_rtx
,
517 gen_int_mode (cfun
->machine
->save_regs_offset
518 - total_frame_size
, Pmode
)));
519 RTX_FRAME_RELATED_P (insn
) = 1;
521 sp_offset
= -cfun
->machine
->save_regs_offset
;
523 else if (total_frame_size
)
525 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
,
526 gen_int_mode (-total_frame_size
,
528 RTX_FRAME_RELATED_P (insn
) = 1;
529 save_regs_base
= cfun
->machine
->save_regs_offset
;
533 save_regs_base
= sp_offset
= 0;
535 if (crtl
->limit_stack
)
536 nios2_emit_stack_limit_check ();
538 save_offset
= save_regs_base
+ cfun
->machine
->save_reg_size
;
540 for (regno
= LAST_GP_REG
; regno
> 0; regno
--)
541 if (cfun
->machine
->save_mask
& (1 << regno
))
544 save_reg (regno
, save_offset
);
547 if (frame_pointer_needed
)
549 int fp_save_offset
= save_regs_base
+ cfun
->machine
->fp_save_offset
;
550 insn
= emit_insn (gen_add3_insn (hard_frame_pointer_rtx
,
552 gen_int_mode (fp_save_offset
, Pmode
)));
553 RTX_FRAME_RELATED_P (insn
) = 1;
559 = gen_rtx_SET (stack_pointer_rtx
,
560 plus_constant (Pmode
, stack_pointer_rtx
, sp_offset
));
561 if (SMALL_INT (sp_offset
))
562 insn
= emit_insn (sp_adjust
);
565 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
566 emit_move_insn (tmp
, gen_int_mode (sp_offset
, Pmode
));
567 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
, tmp
));
568 /* Attach the sp_adjust as a note indicating what happened. */
569 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
, sp_adjust
);
571 RTX_FRAME_RELATED_P (insn
) = 1;
573 if (crtl
->limit_stack
)
574 nios2_emit_stack_limit_check ();
577 /* Load the PIC register if needed. */
578 if (crtl
->uses_pic_offset_table
)
579 nios2_load_pic_register ();
581 /* If we are profiling, make sure no instructions are scheduled before
582 the call to mcount. */
584 emit_insn (gen_blockage ());
588 nios2_expand_epilogue (bool sibcall_p
)
591 int total_frame_size
;
592 int sp_adjust
, save_offset
;
595 if (!sibcall_p
&& nios2_can_use_return_insn ())
597 emit_jump_insn (gen_return ());
601 emit_insn (gen_blockage ());
603 total_frame_size
= nios2_compute_frame_layout ();
604 if (frame_pointer_needed
)
606 /* Recover the stack pointer. */
607 insn
= emit_insn (gen_add3_insn
608 (stack_pointer_rtx
, hard_frame_pointer_rtx
,
609 gen_int_mode (-cfun
->machine
->fp_save_offset
, Pmode
)));
610 cfa_adj
= plus_constant (Pmode
, stack_pointer_rtx
,
612 - cfun
->machine
->save_regs_offset
));
613 add_reg_note (insn
, REG_CFA_DEF_CFA
, cfa_adj
);
614 RTX_FRAME_RELATED_P (insn
) = 1;
617 sp_adjust
= total_frame_size
- cfun
->machine
->save_regs_offset
;
619 else if (!SMALL_INT (total_frame_size
))
621 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
622 emit_move_insn (tmp
, gen_int_mode (cfun
->machine
->save_regs_offset
,
624 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
, tmp
));
625 cfa_adj
= gen_rtx_SET (stack_pointer_rtx
,
626 plus_constant (Pmode
, stack_pointer_rtx
,
627 cfun
->machine
->save_regs_offset
));
628 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, cfa_adj
);
629 RTX_FRAME_RELATED_P (insn
) = 1;
631 sp_adjust
= total_frame_size
- cfun
->machine
->save_regs_offset
;
635 save_offset
= cfun
->machine
->save_regs_offset
;
636 sp_adjust
= total_frame_size
;
639 save_offset
+= cfun
->machine
->save_reg_size
;
641 for (regno
= LAST_GP_REG
; regno
> 0; regno
--)
642 if (cfun
->machine
->save_mask
& (1 << regno
))
645 restore_reg (regno
, save_offset
);
650 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
,
651 gen_int_mode (sp_adjust
, Pmode
)));
652 cfa_adj
= gen_rtx_SET (stack_pointer_rtx
,
653 plus_constant (Pmode
, stack_pointer_rtx
,
655 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, cfa_adj
);
656 RTX_FRAME_RELATED_P (insn
) = 1;
659 /* Add in the __builtin_eh_return stack adjustment. */
660 if (crtl
->calls_eh_return
)
661 emit_insn (gen_add2_insn (stack_pointer_rtx
, EH_RETURN_STACKADJ_RTX
));
664 emit_jump_insn (gen_simple_return ());
667 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
668 back to a previous frame. */
670 nios2_get_return_address (int count
)
675 return get_hard_reg_initial_val (Pmode
, RA_REGNO
);
678 /* Emit code to change the current function's return address to
679 ADDRESS. SCRATCH is available as a scratch register, if needed.
680 ADDRESS and SCRATCH are both word-mode GPRs. */
682 nios2_set_return_address (rtx address
, rtx scratch
)
684 nios2_compute_frame_layout ();
685 if (cfun
->machine
->save_mask
& (1 << RA_REGNO
))
687 unsigned offset
= cfun
->machine
->save_reg_size
- 4;
690 if (frame_pointer_needed
)
691 base
= hard_frame_pointer_rtx
;
694 base
= stack_pointer_rtx
;
695 offset
+= cfun
->machine
->save_regs_offset
;
697 if (!SMALL_INT (offset
))
699 emit_move_insn (scratch
, gen_int_mode (offset
, Pmode
));
700 emit_insn (gen_add2_insn (scratch
, base
));
706 base
= plus_constant (Pmode
, base
, offset
);
707 emit_move_insn (gen_rtx_MEM (Pmode
, base
), address
);
710 emit_move_insn (gen_rtx_REG (Pmode
, RA_REGNO
), address
);
713 /* Implement FUNCTION_PROFILER macro. */
715 nios2_function_profiler (FILE *file
, int labelno ATTRIBUTE_UNUSED
)
717 fprintf (file
, "\tmov\tr8, ra\n");
720 fprintf (file
, "\tnextpc\tr2\n");
721 fprintf (file
, "\t1: movhi\tr3, %%hiadj(_gp_got - 1b)\n");
722 fprintf (file
, "\taddi\tr3, r3, %%lo(_gp_got - 1b)\n");
723 fprintf (file
, "\tadd\tr2, r2, r3\n");
724 fprintf (file
, "\tldw\tr2, %%call(_mcount)(r2)\n");
725 fprintf (file
, "\tcallr\tr2\n");
727 else if (flag_pic
== 2)
729 fprintf (file
, "\tnextpc\tr2\n");
730 fprintf (file
, "\t1: movhi\tr3, %%hiadj(_gp_got - 1b)\n");
731 fprintf (file
, "\taddi\tr3, r3, %%lo(_gp_got - 1b)\n");
732 fprintf (file
, "\tadd\tr2, r2, r3\n");
733 fprintf (file
, "\tmovhi\tr3, %%call_hiadj(_mcount)\n");
734 fprintf (file
, "\taddi\tr3, r3, %%call_lo(_mcount)\n");
735 fprintf (file
, "\tadd\tr3, r2, r3\n");
736 fprintf (file
, "\tldw\tr2, 0(r3)\n");
737 fprintf (file
, "\tcallr\tr2\n");
740 fprintf (file
, "\tcall\t_mcount\n");
741 fprintf (file
, "\tmov\tra, r8\n");
744 /* Dump stack layout. */
746 nios2_dump_frame_layout (FILE *file
)
748 fprintf (file
, "\t%s Current Frame Info\n", ASM_COMMENT_START
);
749 fprintf (file
, "\t%s total_size = %d\n", ASM_COMMENT_START
,
750 cfun
->machine
->total_size
);
751 fprintf (file
, "\t%s var_size = %d\n", ASM_COMMENT_START
,
752 cfun
->machine
->var_size
);
753 fprintf (file
, "\t%s args_size = %d\n", ASM_COMMENT_START
,
754 cfun
->machine
->args_size
);
755 fprintf (file
, "\t%s save_reg_size = %d\n", ASM_COMMENT_START
,
756 cfun
->machine
->save_reg_size
);
757 fprintf (file
, "\t%s initialized = %d\n", ASM_COMMENT_START
,
758 cfun
->machine
->initialized
);
759 fprintf (file
, "\t%s save_regs_offset = %d\n", ASM_COMMENT_START
,
760 cfun
->machine
->save_regs_offset
);
761 fprintf (file
, "\t%s is_leaf = %d\n", ASM_COMMENT_START
,
763 fprintf (file
, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START
,
764 frame_pointer_needed
);
765 fprintf (file
, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START
,
766 crtl
->args
.pretend_args_size
);
769 /* Return true if REGNO should be saved in the prologue. */
771 prologue_saved_reg_p (unsigned regno
)
773 gcc_assert (GP_REG_P (regno
));
775 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
778 if (regno
== HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed
)
781 if (regno
== PIC_OFFSET_TABLE_REGNUM
&& crtl
->uses_pic_offset_table
)
784 if (regno
== RA_REGNO
&& df_regs_ever_live_p (RA_REGNO
))
790 /* Implement TARGET_CAN_ELIMINATE. */
792 nios2_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
794 if (to
== STACK_POINTER_REGNUM
)
795 return !frame_pointer_needed
;
799 /* Implement INITIAL_ELIMINATION_OFFSET macro. */
801 nios2_initial_elimination_offset (int from
, int to
)
805 nios2_compute_frame_layout ();
807 /* Set OFFSET to the offset from the stack pointer. */
810 case FRAME_POINTER_REGNUM
:
811 offset
= cfun
->machine
->args_size
;
814 case ARG_POINTER_REGNUM
:
815 offset
= cfun
->machine
->total_size
;
816 offset
-= crtl
->args
.pretend_args_size
;
823 /* If we are asked for the frame pointer offset, then adjust OFFSET
824 by the offset from the frame pointer to the stack pointer. */
825 if (to
== HARD_FRAME_POINTER_REGNUM
)
826 offset
-= (cfun
->machine
->save_regs_offset
827 + cfun
->machine
->fp_save_offset
);
832 /* Return nonzero if this function is known to have a null epilogue.
833 This allows the optimizer to omit jumps to jumps if no stack
836 nios2_can_use_return_insn (void)
838 if (!reload_completed
|| crtl
->profile
)
841 return nios2_compute_frame_layout () == 0;
845 /* Check and signal some warnings/errors on FPU insn options. */
847 nios2_custom_check_insns (void)
852 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
853 if (N2FPU_ENABLED_P (i
) && N2FPU_DOUBLE_P (i
))
855 for (j
= 0; j
< ARRAY_SIZE (nios2_fpu_insn
); j
++)
856 if (N2FPU_DOUBLE_REQUIRED_P (j
) && ! N2FPU_ENABLED_P (j
))
858 error ("switch %<-mcustom-%s%> is required for double "
859 "precision floating point", N2FPU_NAME (j
));
865 /* Warn if the user has certain exotic operations that won't get used
866 without -funsafe-math-optimizations. See expand_builtin () in
868 if (!flag_unsafe_math_optimizations
)
869 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
870 if (N2FPU_ENABLED_P (i
) && N2FPU_UNSAFE_P (i
))
871 warning (0, "switch %<-mcustom-%s%> has no effect unless "
872 "-funsafe-math-optimizations is specified", N2FPU_NAME (i
));
874 /* Warn if the user is trying to use -mcustom-fmins et. al, that won't
875 get used without -ffinite-math-only. See fold_builtin_fmin_fmax ()
877 if (!flag_finite_math_only
)
878 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
879 if (N2FPU_ENABLED_P (i
) && N2FPU_FINITE_P (i
))
880 warning (0, "switch %<-mcustom-%s%> has no effect unless "
881 "-ffinite-math-only is specified", N2FPU_NAME (i
));
883 /* Warn if the user is trying to use a custom rounding instruction
884 that won't get used without -fno-math-errno. See
885 expand_builtin_int_roundingfn_2 () in builtins.c. */
887 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
888 if (N2FPU_ENABLED_P (i
) && N2FPU_NO_ERRNO_P (i
))
889 warning (0, "switch %<-mcustom-%s%> has no effect unless "
890 "-fno-math-errno is specified", N2FPU_NAME (i
));
892 if (errors
|| custom_code_conflict
)
893 fatal_error (input_location
,
894 "conflicting use of -mcustom switches, target attributes, "
895 "and/or __builtin_custom_ functions");
899 nios2_set_fpu_custom_code (enum n2fpu_code code
, int n
, bool override_p
)
901 if (override_p
|| N2FPU_N (code
) == -1)
903 nios2_register_custom_code (n
, CCS_FPU
, (int) code
);
906 /* Type to represent a standard FPU config. */
907 struct nios2_fpu_config
910 bool set_sp_constants
;
911 int code
[n2fpu_code_num
];
914 #define NIOS2_FPU_CONFIG_NUM 3
915 static struct nios2_fpu_config custom_fpu_config
[NIOS2_FPU_CONFIG_NUM
];
918 nios2_init_fpu_configs (void)
920 struct nios2_fpu_config
* cfg
;
922 #define NEXT_FPU_CONFIG \
924 cfg = &custom_fpu_config[i++]; \
925 memset (cfg, -1, sizeof (struct nios2_fpu_config));\
930 cfg
->set_sp_constants
= true;
931 cfg
->code
[n2fpu_fmuls
] = 252;
932 cfg
->code
[n2fpu_fadds
] = 253;
933 cfg
->code
[n2fpu_fsubs
] = 254;
937 cfg
->set_sp_constants
= true;
938 cfg
->code
[n2fpu_fmuls
] = 252;
939 cfg
->code
[n2fpu_fadds
] = 253;
940 cfg
->code
[n2fpu_fsubs
] = 254;
941 cfg
->code
[n2fpu_fdivs
] = 255;
945 cfg
->set_sp_constants
= true;
946 cfg
->code
[n2fpu_floatus
] = 243;
947 cfg
->code
[n2fpu_fixsi
] = 244;
948 cfg
->code
[n2fpu_floatis
] = 245;
949 cfg
->code
[n2fpu_fcmpgts
] = 246;
950 cfg
->code
[n2fpu_fcmples
] = 249;
951 cfg
->code
[n2fpu_fcmpeqs
] = 250;
952 cfg
->code
[n2fpu_fcmpnes
] = 251;
953 cfg
->code
[n2fpu_fmuls
] = 252;
954 cfg
->code
[n2fpu_fadds
] = 253;
955 cfg
->code
[n2fpu_fsubs
] = 254;
956 cfg
->code
[n2fpu_fdivs
] = 255;
958 #undef NEXT_FPU_CONFIG
959 gcc_assert (i
== NIOS2_FPU_CONFIG_NUM
);
962 static struct nios2_fpu_config
*
963 nios2_match_custom_fpu_cfg (const char *cfgname
, const char *endp
)
966 for (i
= 0; i
< NIOS2_FPU_CONFIG_NUM
; i
++)
968 bool match
= !(endp
!= NULL
969 ? strncmp (custom_fpu_config
[i
].name
, cfgname
,
971 : strcmp (custom_fpu_config
[i
].name
, cfgname
));
973 return &custom_fpu_config
[i
];
978 /* Use CFGNAME to lookup FPU config, ENDP if not NULL marks end of string.
979 OVERRIDE is true if loaded config codes should overwrite current state. */
981 nios2_handle_custom_fpu_cfg (const char *cfgname
, const char *endp
,
984 struct nios2_fpu_config
*cfg
= nios2_match_custom_fpu_cfg (cfgname
, endp
);
988 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
989 if (cfg
->code
[i
] >= 0)
990 nios2_set_fpu_custom_code ((enum n2fpu_code
) i
, cfg
->code
[i
],
992 if (cfg
->set_sp_constants
)
993 flag_single_precision_constant
= 1;
996 warning (0, "ignoring unrecognized switch %<-mcustom-fpu-cfg%> "
997 "value %<%s%>", cfgname
);
999 /* Guard against errors in the standard configurations. */
1000 nios2_custom_check_insns ();
1003 /* Check individual FPU insn options, and register custom code. */
1005 nios2_handle_custom_fpu_insn_option (int fpu_insn_index
)
1007 int param
= N2FPU_N (fpu_insn_index
);
1009 if (0 <= param
&& param
<= 255)
1010 nios2_register_custom_code (param
, CCS_FPU
, fpu_insn_index
);
1012 /* Valid values are 0-255, but also allow -1 so that the
1013 -mno-custom-<opt> switches work. */
1014 else if (param
!= -1)
1015 error ("switch %<-mcustom-%s%> value %d must be between 0 and 255",
1016 N2FPU_NAME (fpu_insn_index
), param
);
1019 /* Allocate a chunk of memory for per-function machine-dependent data. */
1020 static struct machine_function
*
1021 nios2_init_machine_status (void)
1023 return ggc_cleared_alloc
<machine_function
> ();
1026 /* Implement TARGET_OPTION_OVERRIDE. */
1028 nios2_option_override (void)
1032 #ifdef SUBTARGET_OVERRIDE_OPTIONS
1033 SUBTARGET_OVERRIDE_OPTIONS
;
1036 /* Check for unsupported options. */
1037 if (flag_pic
&& !TARGET_LINUX_ABI
)
1038 sorry ("position-independent code requires the Linux ABI");
1040 /* Function to allocate machine-dependent function status. */
1041 init_machine_status
= &nios2_init_machine_status
;
1043 nios2_section_threshold
1044 = (global_options_set
.x_g_switch_value
1045 ? g_switch_value
: NIOS2_DEFAULT_GVALUE
);
1047 if (nios2_gpopt_option
== gpopt_unspecified
)
1049 /* Default to -mgpopt unless -fpic or -fPIC. */
1051 nios2_gpopt_option
= gpopt_none
;
1053 nios2_gpopt_option
= gpopt_local
;
1056 /* If we don't have mul, we don't have mulx either! */
1057 if (!TARGET_HAS_MUL
&& TARGET_HAS_MULX
)
1058 target_flags
&= ~MASK_HAS_MULX
;
1060 /* Initialize default FPU configurations. */
1061 nios2_init_fpu_configs ();
1063 /* Set up default handling for floating point custom instructions.
1065 Putting things in this order means that the -mcustom-fpu-cfg=
1066 switch will always be overridden by individual -mcustom-fadds=
1067 switches, regardless of the order in which they were specified
1068 on the command line.
1070 This behavior of prioritization of individual -mcustom-<insn>=
1071 options before the -mcustom-fpu-cfg= switch is maintained for
1073 if (nios2_custom_fpu_cfg_string
&& *nios2_custom_fpu_cfg_string
)
1074 nios2_handle_custom_fpu_cfg (nios2_custom_fpu_cfg_string
, NULL
, false);
1076 /* Handle options for individual FPU insns. */
1077 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
1078 nios2_handle_custom_fpu_insn_option (i
);
1080 nios2_custom_check_insns ();
1082 /* Save the initial options in case the user does function specific
1084 target_option_default_node
= target_option_current_node
1085 = build_target_option_node (&global_options
);
1089 /* Return true if CST is a constant within range of movi/movui/movhi. */
1091 nios2_simple_const_p (const_rtx cst
)
1093 HOST_WIDE_INT val
= INTVAL (cst
);
1094 return SMALL_INT (val
) || SMALL_INT_UNSIGNED (val
) || UPPER16_INT (val
);
1097 /* Compute a (partial) cost for rtx X. Return true if the complete
1098 cost has been computed, and false if subexpressions should be
1099 scanned. In either case, *TOTAL contains the cost result. */
1101 nios2_rtx_costs (rtx x
, int code
, int outer_code ATTRIBUTE_UNUSED
,
1102 int opno ATTRIBUTE_UNUSED
,
1103 int *total
, bool speed ATTRIBUTE_UNUSED
)
1108 if (INTVAL (x
) == 0)
1110 *total
= COSTS_N_INSNS (0);
1113 else if (nios2_simple_const_p (x
))
1115 *total
= COSTS_N_INSNS (2);
1120 *total
= COSTS_N_INSNS (4);
1129 *total
= COSTS_N_INSNS (4);
1135 /* Recognize 'nor' insn pattern. */
1136 if (GET_CODE (XEXP (x
, 0)) == NOT
1137 && GET_CODE (XEXP (x
, 1)) == NOT
)
1139 *total
= COSTS_N_INSNS (1);
1147 *total
= COSTS_N_INSNS (1);
1152 *total
= COSTS_N_INSNS (3);
1157 *total
= COSTS_N_INSNS (1);
1166 /* Implement TARGET_PREFERRED_RELOAD_CLASS. */
1168 nios2_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, reg_class_t regclass
)
1170 return regclass
== NO_REGS
? GENERAL_REGS
: regclass
;
1173 /* Emit a call to __tls_get_addr. TI is the argument to this function.
1174 RET is an RTX for the return value location. The entire insn sequence
1176 static GTY(()) rtx nios2_tls_symbol
;
1179 nios2_call_tls_get_addr (rtx ti
)
1181 rtx arg
= gen_rtx_REG (Pmode
, FIRST_ARG_REGNO
);
1182 rtx ret
= gen_rtx_REG (Pmode
, FIRST_RETVAL_REGNO
);
1185 if (!nios2_tls_symbol
)
1186 nios2_tls_symbol
= init_one_libfunc ("__tls_get_addr");
1188 emit_move_insn (arg
, ti
);
1189 fn
= gen_rtx_MEM (QImode
, nios2_tls_symbol
);
1190 insn
= emit_call_insn (gen_call_value (ret
, fn
, const0_rtx
));
1191 RTL_CONST_CALL_P (insn
) = 1;
1192 use_reg (&CALL_INSN_FUNCTION_USAGE (insn
), ret
);
1193 use_reg (&CALL_INSN_FUNCTION_USAGE (insn
), arg
);
1198 /* Return true for large offsets requiring hiadj/lo relocation pairs. */
1200 nios2_large_offset_p (int unspec
)
1202 gcc_assert (nios2_unspec_reloc_name (unspec
) != NULL
);
1205 /* FIXME: TLS GOT offset relocations will eventually also get this
1206 treatment, after binutils support for those are also completed. */
1207 && (unspec
== UNSPEC_PIC_SYM
|| unspec
== UNSPEC_PIC_CALL_SYM
))
1210 /* 'gotoff' offsets are always hiadj/lo. */
1211 if (unspec
== UNSPEC_PIC_GOTOFF_SYM
)
1217 /* Return true for conforming unspec relocations. Also used in
1218 constraints.md and predicates.md. */
1220 nios2_unspec_reloc_p (rtx op
)
1222 return (GET_CODE (op
) == CONST
1223 && GET_CODE (XEXP (op
, 0)) == UNSPEC
1224 && ! nios2_large_offset_p (XINT (XEXP (op
, 0), 1)));
1227 /* Helper to generate unspec constant. */
1229 nios2_unspec_offset (rtx loc
, int unspec
)
1231 return gen_rtx_CONST (Pmode
, gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, loc
),
1235 /* Generate GOT pointer based address with large offset. */
1237 nios2_large_got_address (rtx offset
, rtx tmp
)
1240 tmp
= gen_reg_rtx (Pmode
);
1241 emit_move_insn (tmp
, offset
);
1242 return gen_rtx_PLUS (Pmode
, tmp
, pic_offset_table_rtx
);
1245 /* Generate a GOT pointer based address. */
1247 nios2_got_address (rtx loc
, int unspec
)
1249 rtx offset
= nios2_unspec_offset (loc
, unspec
);
1250 crtl
->uses_pic_offset_table
= 1;
1252 if (nios2_large_offset_p (unspec
))
1253 return force_reg (Pmode
, nios2_large_got_address (offset
, NULL_RTX
));
1255 return gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, offset
);
1258 /* Generate the code to access LOC, a thread local SYMBOL_REF. The
1259 return value will be a valid address and move_operand (either a REG
1262 nios2_legitimize_tls_address (rtx loc
)
1265 enum tls_model model
= SYMBOL_REF_TLS_MODEL (loc
);
1269 case TLS_MODEL_GLOBAL_DYNAMIC
:
1270 tmp
= gen_reg_rtx (Pmode
);
1271 emit_move_insn (tmp
, nios2_got_address (loc
, UNSPEC_ADD_TLS_GD
));
1272 return nios2_call_tls_get_addr (tmp
);
1274 case TLS_MODEL_LOCAL_DYNAMIC
:
1275 tmp
= gen_reg_rtx (Pmode
);
1276 emit_move_insn (tmp
, nios2_got_address (loc
, UNSPEC_ADD_TLS_LDM
));
1277 return gen_rtx_PLUS (Pmode
, nios2_call_tls_get_addr (tmp
),
1278 nios2_unspec_offset (loc
, UNSPEC_ADD_TLS_LDO
));
1280 case TLS_MODEL_INITIAL_EXEC
:
1281 tmp
= gen_reg_rtx (Pmode
);
1282 mem
= gen_const_mem (Pmode
, nios2_got_address (loc
, UNSPEC_LOAD_TLS_IE
));
1283 emit_move_insn (tmp
, mem
);
1284 tp
= gen_rtx_REG (Pmode
, TP_REGNO
);
1285 return gen_rtx_PLUS (Pmode
, tp
, tmp
);
1287 case TLS_MODEL_LOCAL_EXEC
:
1288 tp
= gen_rtx_REG (Pmode
, TP_REGNO
);
1289 return gen_rtx_PLUS (Pmode
, tp
,
1290 nios2_unspec_offset (loc
, UNSPEC_ADD_TLS_LE
));
1298 If -O3 is used, we want to output a table lookup for
1299 divides between small numbers (both num and den >= 0
1300 and < 0x10). The overhead of this method in the worst
1301 case is 40 bytes in the text section (10 insns) and
1302 256 bytes in the data section. Additional divides do
1303 not incur additional penalties in the data section.
1305 Code speed is improved for small divides by about 5x
1306 when using this method in the worse case (~9 cycles
1307 vs ~45). And in the worst case divides not within the
1308 table are penalized by about 10% (~5 cycles vs ~45).
1309 However in the typical case the penalty is not as bad
1310 because doing the long divide in only 45 cycles is
1313 ??? would be nice to have some benchmarks other
1314 than Dhrystone to back this up.
1316 This bit of expansion is to create this instruction
1323 add $12, $11, divide_table
1329 # continue here with result in $2
1331 ??? Ideally I would like the libcall block to contain all
1332 of this code, but I don't know how to do that. What it
1333 means is that if the divide can be eliminated, it may not
1334 completely disappear.
1336 ??? The __divsi3_table label should ideally be moved out
1337 of this block and into a global. If it is placed into the
1338 sdata section we can save even more cycles by doing things
1341 nios2_emit_expensive_div (rtx
*operands
, machine_mode mode
)
1343 rtx or_result
, shift_left_result
;
1345 rtx_code_label
*lab1
, *lab3
;
1352 /* It may look a little generic, but only SImode is supported for now. */
1353 gcc_assert (mode
== SImode
);
1354 libfunc
= optab_libfunc (sdiv_optab
, SImode
);
1356 lab1
= gen_label_rtx ();
1357 lab3
= gen_label_rtx ();
1359 or_result
= expand_simple_binop (SImode
, IOR
,
1360 operands
[1], operands
[2],
1361 0, 0, OPTAB_LIB_WIDEN
);
1363 emit_cmp_and_jump_insns (or_result
, GEN_INT (15), GTU
, 0,
1364 GET_MODE (or_result
), 0, lab3
);
1365 JUMP_LABEL (get_last_insn ()) = lab3
;
1367 shift_left_result
= expand_simple_binop (SImode
, ASHIFT
,
1368 operands
[1], GEN_INT (4),
1369 0, 0, OPTAB_LIB_WIDEN
);
1371 lookup_value
= expand_simple_binop (SImode
, IOR
,
1372 shift_left_result
, operands
[2],
1373 0, 0, OPTAB_LIB_WIDEN
);
1374 table
= gen_rtx_PLUS (SImode
, lookup_value
,
1375 gen_rtx_SYMBOL_REF (SImode
, "__divsi3_table"));
1376 convert_move (operands
[0], gen_rtx_MEM (QImode
, table
), 1);
1378 tmp
= emit_jump_insn (gen_jump (lab1
));
1379 JUMP_LABEL (tmp
) = lab1
;
1383 LABEL_NUSES (lab3
) = 1;
1386 final_result
= emit_library_call_value (libfunc
, NULL_RTX
,
1387 LCT_CONST
, SImode
, 2,
1388 operands
[1], SImode
,
1389 operands
[2], SImode
);
1391 insns
= get_insns ();
1393 emit_libcall_block (insns
, operands
[0], final_result
,
1394 gen_rtx_DIV (SImode
, operands
[1], operands
[2]));
1397 LABEL_NUSES (lab1
) = 1;
1401 /* Branches and compares. */
1403 /* Return in *ALT_CODE and *ALT_OP, an alternate equivalent constant
1404 comparison, e.g. >= 1 into > 0. */
1406 nios2_alternate_compare_const (enum rtx_code code
, rtx op
,
1407 enum rtx_code
*alt_code
, rtx
*alt_op
,
1410 HOST_WIDE_INT opval
= INTVAL (op
);
1411 enum rtx_code scode
= signed_condition (code
);
1412 bool dec_p
= (scode
== LT
|| scode
== GE
);
1414 if (code
== EQ
|| code
== NE
)
1422 ? gen_int_mode (opval
- 1, mode
)
1423 : gen_int_mode (opval
+ 1, mode
));
1425 /* The required conversion between [>,>=] and [<,<=] is captured
1426 by a reverse + swap of condition codes. */
1427 *alt_code
= reverse_condition (swap_condition (code
));
1430 /* Test if the incremented/decremented value crosses the over/underflow
1431 boundary. Supposedly, such boundary cases should already be transformed
1432 into always-true/false or EQ conditions, so use an assertion here. */
1433 unsigned HOST_WIDE_INT alt_opval
= INTVAL (*alt_op
);
1435 alt_opval
^= (1 << (GET_MODE_BITSIZE (mode
) - 1));
1436 alt_opval
&= GET_MODE_MASK (mode
);
1437 gcc_assert (dec_p
? alt_opval
!= GET_MODE_MASK (mode
) : alt_opval
!= 0);
1441 /* Return true if the constant comparison is supported by nios2. */
1443 nios2_valid_compare_const_p (enum rtx_code code
, rtx op
)
1447 case EQ
: case NE
: case GE
: case LT
:
1448 return SMALL_INT (INTVAL (op
));
1450 return SMALL_INT_UNSIGNED (INTVAL (op
));
1456 /* Checks if the FPU comparison in *CMP, *OP1, and *OP2 can be supported in
1457 the current configuration. Perform modifications if MODIFY_P is true.
1458 Returns true if FPU compare can be done. */
1461 nios2_validate_fpu_compare (machine_mode mode
, rtx
*cmp
, rtx
*op1
, rtx
*op2
,
1465 enum rtx_code code
= GET_CODE (*cmp
);
1467 if (!nios2_fpu_compare_enabled (code
, mode
))
1469 code
= swap_condition (code
);
1470 if (nios2_fpu_compare_enabled (code
, mode
))
1484 *op1
= force_reg (mode
, *op1
);
1485 *op2
= force_reg (mode
, *op2
);
1486 *cmp
= gen_rtx_fmt_ee (code
, mode
, *op1
, *op2
);
1491 /* Checks and modifies the comparison in *CMP, *OP1, and *OP2 into valid
1492 nios2 supported form. Returns true if success. */
1494 nios2_validate_compare (machine_mode mode
, rtx
*cmp
, rtx
*op1
, rtx
*op2
)
1496 enum rtx_code code
= GET_CODE (*cmp
);
1497 enum rtx_code alt_code
;
1500 if (GET_MODE_CLASS (mode
) == MODE_FLOAT
)
1501 return nios2_validate_fpu_compare (mode
, cmp
, op1
, op2
, true);
1503 if (!reg_or_0_operand (*op2
, mode
))
1505 /* Create alternate constant compare. */
1506 nios2_alternate_compare_const (code
, *op2
, &alt_code
, &alt_op2
, mode
);
1508 /* If alterate op2 is zero(0), we can use it directly, possibly
1509 swapping the compare code. */
1510 if (alt_op2
== const0_rtx
)
1514 goto check_rebuild_cmp
;
1517 /* Check if either constant compare can be used. */
1518 if (nios2_valid_compare_const_p (code
, *op2
))
1520 else if (nios2_valid_compare_const_p (alt_code
, alt_op2
))
1527 /* We have to force op2 into a register now. Try to pick one
1528 with a lower cost. */
1529 if (! nios2_simple_const_p (*op2
)
1530 && nios2_simple_const_p (alt_op2
))
1535 *op2
= force_reg (SImode
, *op2
);
1538 if (code
== GT
|| code
== GTU
|| code
== LE
|| code
== LEU
)
1540 rtx t
= *op1
; *op1
= *op2
; *op2
= t
;
1541 code
= swap_condition (code
);
1544 *cmp
= gen_rtx_fmt_ee (code
, mode
, *op1
, *op2
);
1549 /* Addressing Modes. */
1551 /* Implement TARGET_LEGITIMATE_CONSTANT_P. */
1553 nios2_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
1556 split_const (x
, &base
, &offset
);
1557 return GET_CODE (base
) != SYMBOL_REF
|| !SYMBOL_REF_TLS_MODEL (base
);
1560 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
1562 nios2_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
1564 return nios2_legitimate_constant_p (mode
, x
) == false;
1567 /* Return true if register REGNO is a valid base register.
1568 STRICT_P is true if REG_OK_STRICT is in effect. */
1571 nios2_regno_ok_for_base_p (int regno
, bool strict_p
)
1573 if (!HARD_REGISTER_NUM_P (regno
))
1581 regno
= reg_renumber
[regno
];
1584 /* The fake registers will be eliminated to either the stack or
1585 hard frame pointer, both of which are usually valid base registers.
1586 Reload deals with the cases where the eliminated form isn't valid. */
1587 return (GP_REG_P (regno
)
1588 || regno
== FRAME_POINTER_REGNUM
1589 || regno
== ARG_POINTER_REGNUM
);
1592 /* Return true if the address expression formed by BASE + OFFSET is
1595 nios2_valid_addr_expr_p (rtx base
, rtx offset
, bool strict_p
)
1597 if (!strict_p
&& GET_CODE (base
) == SUBREG
)
1598 base
= SUBREG_REG (base
);
1599 return (REG_P (base
)
1600 && nios2_regno_ok_for_base_p (REGNO (base
), strict_p
)
1601 && (offset
== NULL_RTX
1602 || const_arith_operand (offset
, Pmode
)
1603 || nios2_unspec_reloc_p (offset
)));
1606 /* Implement TARGET_LEGITIMATE_ADDRESS_P. */
1608 nios2_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED
,
1609 rtx operand
, bool strict_p
)
1611 switch (GET_CODE (operand
))
1615 if (SYMBOL_REF_TLS_MODEL (operand
))
1618 if (nios2_symbol_ref_in_small_data_p (operand
))
1621 /* Else, fall through. */
1628 /* Register indirect. */
1630 return nios2_regno_ok_for_base_p (REGNO (operand
), strict_p
);
1632 /* Register indirect with displacement. */
1635 rtx op0
= XEXP (operand
, 0);
1636 rtx op1
= XEXP (operand
, 1);
1638 return (nios2_valid_addr_expr_p (op0
, op1
, strict_p
)
1639 || nios2_valid_addr_expr_p (op1
, op0
, strict_p
));
1648 /* Return true if SECTION is a small section name. */
1650 nios2_small_section_name_p (const char *section
)
1652 return (strcmp (section
, ".sbss") == 0
1653 || strncmp (section
, ".sbss.", 6) == 0
1654 || strcmp (section
, ".sdata") == 0
1655 || strncmp (section
, ".sdata.", 7) == 0);
1658 /* Return true if EXP should be placed in the small data section. */
1660 nios2_in_small_data_p (const_tree exp
)
1662 /* We want to merge strings, so we never consider them small data. */
1663 if (TREE_CODE (exp
) == STRING_CST
)
1666 if (TREE_CODE (exp
) == VAR_DECL
)
1668 if (DECL_SECTION_NAME (exp
))
1670 const char *section
= DECL_SECTION_NAME (exp
);
1671 if (nios2_small_section_name_p (section
))
1676 HOST_WIDE_INT size
= int_size_in_bytes (TREE_TYPE (exp
));
1678 /* If this is an incomplete type with size 0, then we can't put it
1679 in sdata because it might be too big when completed. */
1681 && (unsigned HOST_WIDE_INT
) size
<= nios2_section_threshold
)
1689 /* Return true if symbol is in small data section. */
1692 nios2_symbol_ref_in_small_data_p (rtx sym
)
1696 gcc_assert (GET_CODE (sym
) == SYMBOL_REF
);
1697 decl
= SYMBOL_REF_DECL (sym
);
1699 /* TLS variables are not accessed through the GP. */
1700 if (SYMBOL_REF_TLS_MODEL (sym
) != 0)
1703 /* If the user has explicitly placed the symbol in a small data section
1704 via an attribute, generate gp-relative addressing even if the symbol
1705 is external, weak, or larger than we'd automatically put in the
1706 small data section. OTOH, if the symbol is located in some
1707 non-small-data section, we can't use gp-relative accesses on it
1708 unless the user has requested gpopt_data or gpopt_all. */
1710 switch (nios2_gpopt_option
)
1713 /* Don't generate a gp-relative addressing mode if that's been
1718 /* Use GP-relative addressing for small data symbols that are
1719 not external or weak, plus any symbols that have explicitly
1720 been placed in a small data section. */
1721 if (decl
&& DECL_SECTION_NAME (decl
))
1722 return nios2_small_section_name_p (DECL_SECTION_NAME (decl
));
1723 return (SYMBOL_REF_SMALL_P (sym
)
1724 && !SYMBOL_REF_EXTERNAL_P (sym
)
1725 && !(decl
&& DECL_WEAK (decl
)));
1728 /* Use GP-relative addressing for small data symbols, even if
1729 they are external or weak. Note that SYMBOL_REF_SMALL_P
1730 is also true of symbols that have explicitly been placed
1731 in a small data section. */
1732 return SYMBOL_REF_SMALL_P (sym
);
1735 /* Use GP-relative addressing for all data symbols regardless
1736 of the object size, but not for code symbols. This option
1737 is equivalent to the user asserting that the entire data
1738 section is accessible from the GP. */
1739 return !SYMBOL_REF_FUNCTION_P (sym
);
1742 /* Use GP-relative addressing for everything, including code.
1743 Effectively, the user has asserted that the entire program
1744 fits within the 64K range of the GP offset. */
1748 /* We shouldn't get here. */
1753 /* Implement TARGET_SECTION_TYPE_FLAGS. */
1756 nios2_section_type_flags (tree decl
, const char *name
, int reloc
)
1760 flags
= default_section_type_flags (decl
, name
, reloc
);
1762 if (nios2_small_section_name_p (name
))
1763 flags
|= SECTION_SMALL
;
1768 /* Return true if SYMBOL_REF X binds locally. */
1771 nios2_symbol_binds_local_p (const_rtx x
)
1773 return (SYMBOL_REF_DECL (x
)
1774 ? targetm
.binds_local_p (SYMBOL_REF_DECL (x
))
1775 : SYMBOL_REF_LOCAL_P (x
));
1778 /* Position independent code related. */
1780 /* Emit code to load the PIC register. */
1782 nios2_load_pic_register (void)
1784 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
1786 emit_insn (gen_load_got_register (pic_offset_table_rtx
, tmp
));
1787 emit_insn (gen_add3_insn (pic_offset_table_rtx
, pic_offset_table_rtx
, tmp
));
1790 /* Generate a PIC address as a MEM rtx. */
1792 nios2_load_pic_address (rtx sym
, int unspec
, rtx tmp
)
1795 && GET_CODE (sym
) == SYMBOL_REF
1796 && nios2_symbol_binds_local_p (sym
))
1797 /* Under -fPIC, generate a GOTOFF address for local symbols. */
1799 rtx offset
= nios2_unspec_offset (sym
, UNSPEC_PIC_GOTOFF_SYM
);
1800 crtl
->uses_pic_offset_table
= 1;
1801 return nios2_large_got_address (offset
, tmp
);
1804 return gen_const_mem (Pmode
, nios2_got_address (sym
, unspec
));
1807 /* Nonzero if the constant value X is a legitimate general operand
1808 when generating PIC code. It is given that flag_pic is on and
1809 that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
1811 nios2_legitimate_pic_operand_p (rtx x
)
1813 if (GET_CODE (x
) == CONST
1814 && GET_CODE (XEXP (x
, 0)) == UNSPEC
1815 && nios2_large_offset_p (XINT (XEXP (x
, 0), 1)))
1818 return ! (GET_CODE (x
) == SYMBOL_REF
1819 || GET_CODE (x
) == LABEL_REF
|| GET_CODE (x
) == CONST
);
1822 /* Return TRUE if X is a thread-local symbol. */
1824 nios2_tls_symbol_p (rtx x
)
1826 return (targetm
.have_tls
&& GET_CODE (x
) == SYMBOL_REF
1827 && SYMBOL_REF_TLS_MODEL (x
) != 0);
1830 /* Legitimize addresses that are CONSTANT_P expressions. */
1832 nios2_legitimize_constant_address (rtx addr
)
1835 split_const (addr
, &base
, &offset
);
1837 if (nios2_tls_symbol_p (base
))
1838 base
= nios2_legitimize_tls_address (base
);
1840 base
= nios2_load_pic_address (base
, UNSPEC_PIC_SYM
, NULL_RTX
);
1844 if (offset
!= const0_rtx
)
1846 gcc_assert (can_create_pseudo_p ());
1847 return gen_rtx_PLUS (Pmode
, force_reg (Pmode
, base
),
1848 (CONST_INT_P (offset
)
1849 ? (SMALL_INT (INTVAL (offset
))
1850 ? offset
: force_reg (Pmode
, offset
))
1856 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1858 nios2_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
1859 machine_mode mode ATTRIBUTE_UNUSED
)
1862 return nios2_legitimize_constant_address (x
);
1864 /* For the TLS LE (Local Exec) model, the compiler may try to
1865 combine constant offsets with unspec relocs, creating address RTXs
1867 (plus:SI (reg:SI 23 r23)
1870 (unspec:SI [(symbol_ref:SI ("var"))] UNSPEC_ADD_TLS_LE)
1871 (const_int 48 [0x30]))))
1873 This usually happens when 'var' is a thread-local struct variable,
1874 and access of a field in var causes the addend.
1876 We typically want this combining, so transform the above into this
1877 form, which is allowed:
1878 (plus:SI (reg:SI 23 r23)
1882 (plus:SI (symbol_ref:SI ("var"))
1883 (const_int 48 [0x30])))] UNSPEC_ADD_TLS_LE)))
1885 Which will be output as '%tls_le(var+48)(r23)' in assembly. */
1886 if (GET_CODE (x
) == PLUS
1887 && GET_CODE (XEXP (x
, 0)) == REG
1888 && GET_CODE (XEXP (x
, 1)) == CONST
)
1890 rtx unspec
, offset
, reg
= XEXP (x
, 0);
1891 split_const (XEXP (x
, 1), &unspec
, &offset
);
1892 if (GET_CODE (unspec
) == UNSPEC
1893 && !nios2_large_offset_p (XINT (unspec
, 1))
1894 && offset
!= const0_rtx
)
1896 unspec
= copy_rtx (unspec
);
1897 XVECEXP (unspec
, 0, 0)
1898 = plus_constant (Pmode
, XVECEXP (unspec
, 0, 0), INTVAL (offset
));
1899 x
= gen_rtx_PLUS (Pmode
, reg
, gen_rtx_CONST (Pmode
, unspec
));
1907 nios2_delegitimize_address (rtx x
)
1909 x
= delegitimize_mem_from_attrs (x
);
1911 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == UNSPEC
)
1913 switch (XINT (XEXP (x
, 0), 1))
1915 case UNSPEC_PIC_SYM
:
1916 case UNSPEC_PIC_CALL_SYM
:
1917 case UNSPEC_PIC_GOTOFF_SYM
:
1918 case UNSPEC_ADD_TLS_GD
:
1919 case UNSPEC_ADD_TLS_LDM
:
1920 case UNSPEC_LOAD_TLS_IE
:
1921 case UNSPEC_ADD_TLS_LE
:
1922 x
= XVECEXP (XEXP (x
, 0), 0, 0);
1923 gcc_assert (CONSTANT_P (x
));
1930 /* Main expander function for RTL moves. */
1932 nios2_emit_move_sequence (rtx
*operands
, machine_mode mode
)
1934 rtx to
= operands
[0];
1935 rtx from
= operands
[1];
1937 if (!register_operand (to
, mode
) && !reg_or_0_operand (from
, mode
))
1939 gcc_assert (can_create_pseudo_p ());
1940 from
= copy_to_mode_reg (mode
, from
);
1943 if (GET_CODE (from
) == SYMBOL_REF
|| GET_CODE (from
) == LABEL_REF
1944 || (GET_CODE (from
) == CONST
1945 && GET_CODE (XEXP (from
, 0)) != UNSPEC
))
1946 from
= nios2_legitimize_constant_address (from
);
1953 /* The function with address *ADDR is being called. If the address
1954 needs to be loaded from the GOT, emit the instruction to do so and
1955 update *ADDR to point to the rtx for the loaded value.
1956 If REG != NULL_RTX, it is used as the target/scratch register in the
1957 GOT address calculation. */
1959 nios2_adjust_call_address (rtx
*call_op
, rtx reg
)
1961 if (MEM_P (*call_op
))
1962 call_op
= &XEXP (*call_op
, 0);
1964 rtx addr
= *call_op
;
1965 if (flag_pic
&& CONSTANT_P (addr
))
1967 rtx tmp
= reg
? reg
: NULL_RTX
;
1969 reg
= gen_reg_rtx (Pmode
);
1970 addr
= nios2_load_pic_address (addr
, UNSPEC_PIC_CALL_SYM
, tmp
);
1971 emit_insn (gen_rtx_SET (reg
, addr
));
1977 /* Output assembly language related definitions. */
1979 /* Print the operand OP to file stream FILE modified by LETTER.
1980 LETTER can be one of:
1982 i: print "i" if OP is an immediate, except 0
1983 o: print "io" if OP is volatile
1984 z: for const0_rtx print $0 instead of 0
1987 U: for upper half of 32 bit value
1988 D: for the upper 32-bits of a 64-bit double value
1989 R: prints reverse condition.
1992 nios2_print_operand (FILE *file
, rtx op
, int letter
)
1998 if (CONSTANT_P (op
) && op
!= const0_rtx
)
1999 fprintf (file
, "i");
2003 if (GET_CODE (op
) == MEM
2004 && ((MEM_VOLATILE_P (op
) && TARGET_BYPASS_CACHE_VOLATILE
)
2005 || TARGET_BYPASS_CACHE
))
2006 fprintf (file
, "io");
2013 if (comparison_operator (op
, VOIDmode
))
2015 enum rtx_code cond
= GET_CODE (op
);
2018 fprintf (file
, "%s", GET_RTX_NAME (cond
));
2023 fprintf (file
, "%s", GET_RTX_NAME (reverse_condition (cond
)));
2028 switch (GET_CODE (op
))
2031 if (letter
== 0 || letter
== 'z')
2033 fprintf (file
, "%s", reg_names
[REGNO (op
)]);
2036 else if (letter
== 'D')
2038 fprintf (file
, "%s", reg_names
[REGNO (op
)+1]);
2044 if (INTVAL (op
) == 0 && letter
== 'z')
2046 fprintf (file
, "zero");
2052 HOST_WIDE_INT val
= INTVAL (op
);
2053 val
= (val
>> 16) & 0xFFFF;
2054 output_addr_const (file
, gen_int_mode (val
, SImode
));
2057 /* Else, fall through. */
2063 if (letter
== 0 || letter
== 'z')
2065 output_addr_const (file
, op
);
2068 else if (letter
== 'H' || letter
== 'L')
2070 fprintf (file
, "%%");
2071 if (GET_CODE (op
) == CONST
2072 && GET_CODE (XEXP (op
, 0)) == UNSPEC
)
2074 rtx unspec
= XEXP (op
, 0);
2075 int unspec_reloc
= XINT (unspec
, 1);
2076 gcc_assert (nios2_large_offset_p (unspec_reloc
));
2077 fprintf (file
, "%s_", nios2_unspec_reloc_name (unspec_reloc
));
2078 op
= XVECEXP (unspec
, 0, 0);
2080 fprintf (file
, letter
== 'H' ? "hiadj(" : "lo(");
2081 output_addr_const (file
, op
);
2082 fprintf (file
, ")");
2091 output_address (op
);
2099 output_addr_const (file
, op
);
2108 output_operand_lossage ("Unsupported operand for code '%c'", letter
);
2112 /* Return true if this is a GP-relative accessible reference. */
2114 gprel_constant_p (rtx op
)
2116 if (GET_CODE (op
) == SYMBOL_REF
2117 && nios2_symbol_ref_in_small_data_p (op
))
2119 else if (GET_CODE (op
) == CONST
2120 && GET_CODE (XEXP (op
, 0)) == PLUS
)
2121 return gprel_constant_p (XEXP (XEXP (op
, 0), 0));
2126 /* Return the name string for a supported unspec reloc offset. */
2128 nios2_unspec_reloc_name (int unspec
)
2132 case UNSPEC_PIC_SYM
:
2134 case UNSPEC_PIC_CALL_SYM
:
2136 case UNSPEC_PIC_GOTOFF_SYM
:
2138 case UNSPEC_LOAD_TLS_IE
:
2140 case UNSPEC_ADD_TLS_LE
:
2142 case UNSPEC_ADD_TLS_GD
:
2144 case UNSPEC_ADD_TLS_LDM
:
2146 case UNSPEC_ADD_TLS_LDO
:
2153 /* Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA. */
2155 nios2_output_addr_const_extra (FILE *file
, rtx op
)
2158 gcc_assert (GET_CODE (op
) == UNSPEC
);
2160 /* Support for printing out const unspec relocations. */
2161 name
= nios2_unspec_reloc_name (XINT (op
, 1));
2164 fprintf (file
, "%%%s(", name
);
2165 output_addr_const (file
, XVECEXP (op
, 0, 0));
2166 fprintf (file
, ")");
2172 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
2174 nios2_print_operand_address (FILE *file
, rtx op
)
2176 switch (GET_CODE (op
))
2183 if (gprel_constant_p (op
))
2185 fprintf (file
, "%%gprel(");
2186 output_addr_const (file
, op
);
2187 fprintf (file
, ")(%s)", reg_names
[GP_REGNO
]);
2195 rtx op0
= XEXP (op
, 0);
2196 rtx op1
= XEXP (op
, 1);
2198 if (REG_P (op0
) && CONSTANT_P (op1
))
2200 output_addr_const (file
, op1
);
2201 fprintf (file
, "(%s)", reg_names
[REGNO (op0
)]);
2204 else if (REG_P (op1
) && CONSTANT_P (op0
))
2206 output_addr_const (file
, op0
);
2207 fprintf (file
, "(%s)", reg_names
[REGNO (op1
)]);
2214 fprintf (file
, "0(%s)", reg_names
[REGNO (op
)]);
2219 rtx base
= XEXP (op
, 0);
2220 nios2_print_operand_address (file
, base
);
2227 fprintf (stderr
, "Missing way to print address\n");
2232 /* Implement TARGET_ASM_OUTPUT_DWARF_DTPREL. */
2234 nios2_output_dwarf_dtprel (FILE *file
, int size
, rtx x
)
2236 gcc_assert (size
== 4);
2237 fprintf (file
, "\t.4byte\t%%tls_ldo(");
2238 output_addr_const (file
, x
);
2239 fprintf (file
, ")");
2242 /* Implemet TARGET_ASM_FILE_END. */
2245 nios2_asm_file_end (void)
2247 /* The Nios II Linux stack is mapped non-executable by default, so add a
2248 .note.GNU-stack section for switching to executable stacks only when
2249 trampolines are generated. */
2250 if (TARGET_LINUX_ABI
&& trampolines_created
)
2251 file_end_indicate_exec_stack ();
2254 /* Implement TARGET_ASM_FUNCTION_PROLOGUE. */
2256 nios2_asm_function_prologue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2258 if (flag_verbose_asm
|| flag_debug_asm
)
2260 nios2_compute_frame_layout ();
2261 nios2_dump_frame_layout (file
);
2265 /* Emit assembly of custom FPU instructions. */
2267 nios2_fpu_insn_asm (enum n2fpu_code code
)
2269 static char buf
[256];
2270 const char *op1
, *op2
, *op3
;
2271 int ln
= 256, n
= 0;
2273 int N
= N2FPU_N (code
);
2274 int num_operands
= N2FPU (code
).num_operands
;
2275 const char *insn_name
= N2FPU_NAME (code
);
2276 tree ftype
= nios2_ftype (N2FPU_FTCODE (code
));
2277 machine_mode dst_mode
= TYPE_MODE (TREE_TYPE (ftype
));
2278 machine_mode src_mode
= TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (ftype
)));
2280 /* Prepare X register for DF input operands. */
2281 if (GET_MODE_SIZE (src_mode
) == 8 && num_operands
== 3)
2282 n
= snprintf (buf
, ln
, "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t",
2283 N2FPU_N (n2fpu_fwrx
));
2285 if (src_mode
== SFmode
)
2287 if (dst_mode
== VOIDmode
)
2289 /* The fwry case. */
2296 op1
= (dst_mode
== DFmode
? "%D0" : "%0");
2298 op3
= (num_operands
== 2 ? "zero" : "%2");
2301 else if (src_mode
== DFmode
)
2303 if (dst_mode
== VOIDmode
)
2305 /* The fwrx case. */
2313 op1
= (dst_mode
== DFmode
? "%D0" : "%0");
2314 op2
= (num_operands
== 2 ? "%1" : "%2");
2315 op3
= (num_operands
== 2 ? "%D1" : "%D2");
2318 else if (src_mode
== VOIDmode
)
2320 /* frdxlo, frdxhi, frdy cases. */
2321 gcc_assert (dst_mode
== SFmode
);
2325 else if (src_mode
== SImode
)
2327 /* Conversion operators. */
2328 gcc_assert (num_operands
== 2);
2329 op1
= (dst_mode
== DFmode
? "%D0" : "%0");
2336 /* Main instruction string. */
2337 n
+= snprintf (buf
+ n
, ln
- n
, "custom\t%d, %s, %s, %s # %s %%0%s%s",
2338 N
, op1
, op2
, op3
, insn_name
,
2339 (num_operands
>= 2 ? ", %1" : ""),
2340 (num_operands
== 3 ? ", %2" : ""));
2342 /* Extraction of Y register for DF results. */
2343 if (dst_mode
== DFmode
)
2344 snprintf (buf
+ n
, ln
- n
, "\n\tcustom\t%d, %%0, zero, zero # frdy %%0",
2345 N2FPU_N (n2fpu_frdy
));
2351 /* Function argument related. */
2353 /* Define where to put the arguments to a function. Value is zero to
2354 push the argument on the stack, or a hard register in which to
2357 MODE is the argument's machine mode.
2358 TYPE is the data type of the argument (as a tree).
2359 This is null for libcalls where that information may
2361 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2362 the preceding args and about the function being called.
2363 NAMED is nonzero if this argument is a named parameter
2364 (otherwise it is an extra parameter matching an ellipsis). */
2367 nios2_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
2368 const_tree type ATTRIBUTE_UNUSED
,
2369 bool named ATTRIBUTE_UNUSED
)
2371 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2372 rtx return_rtx
= NULL_RTX
;
2374 if (cum
->regs_used
< NUM_ARG_REGS
)
2375 return_rtx
= gen_rtx_REG (mode
, FIRST_ARG_REGNO
+ cum
->regs_used
);
2380 /* Return number of bytes, at the beginning of the argument, that must be
2381 put in registers. 0 is the argument is entirely in registers or entirely
2385 nios2_arg_partial_bytes (cumulative_args_t cum_v
,
2386 machine_mode mode
, tree type ATTRIBUTE_UNUSED
,
2387 bool named ATTRIBUTE_UNUSED
)
2389 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2390 HOST_WIDE_INT param_size
;
2392 if (mode
== BLKmode
)
2394 param_size
= int_size_in_bytes (type
);
2395 gcc_assert (param_size
>= 0);
2398 param_size
= GET_MODE_SIZE (mode
);
2400 /* Convert to words (round up). */
2401 param_size
= (UNITS_PER_WORD
- 1 + param_size
) / UNITS_PER_WORD
;
2403 if (cum
->regs_used
< NUM_ARG_REGS
2404 && cum
->regs_used
+ param_size
> NUM_ARG_REGS
)
2405 return (NUM_ARG_REGS
- cum
->regs_used
) * UNITS_PER_WORD
;
2410 /* Update the data in CUM to advance over an argument of mode MODE
2411 and data type TYPE; TYPE is null for libcalls where that information
2412 may not be available. */
2415 nios2_function_arg_advance (cumulative_args_t cum_v
, machine_mode mode
,
2416 const_tree type ATTRIBUTE_UNUSED
,
2417 bool named ATTRIBUTE_UNUSED
)
2419 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2420 HOST_WIDE_INT param_size
;
2422 if (mode
== BLKmode
)
2424 param_size
= int_size_in_bytes (type
);
2425 gcc_assert (param_size
>= 0);
2428 param_size
= GET_MODE_SIZE (mode
);
2430 /* Convert to words (round up). */
2431 param_size
= (UNITS_PER_WORD
- 1 + param_size
) / UNITS_PER_WORD
;
2433 if (cum
->regs_used
+ param_size
> NUM_ARG_REGS
)
2434 cum
->regs_used
= NUM_ARG_REGS
;
2436 cum
->regs_used
+= param_size
;
2440 nios2_function_arg_padding (machine_mode mode
, const_tree type
)
2442 /* On little-endian targets, the first byte of every stack argument
2443 is passed in the first byte of the stack slot. */
2444 if (!BYTES_BIG_ENDIAN
)
2447 /* Otherwise, integral types are padded downward: the last byte of a
2448 stack argument is passed in the last byte of the stack slot. */
2450 ? INTEGRAL_TYPE_P (type
) || POINTER_TYPE_P (type
)
2451 : GET_MODE_CLASS (mode
) == MODE_INT
)
2454 /* Arguments smaller than a stack slot are padded downward. */
2455 if (mode
!= BLKmode
)
2456 return (GET_MODE_BITSIZE (mode
) >= PARM_BOUNDARY
) ? upward
: downward
;
2458 return ((int_size_in_bytes (type
) >= (PARM_BOUNDARY
/ BITS_PER_UNIT
))
2459 ? upward
: downward
);
2463 nios2_block_reg_padding (machine_mode mode
, tree type
,
2464 int first ATTRIBUTE_UNUSED
)
2466 return nios2_function_arg_padding (mode
, type
);
2469 /* Emit RTL insns to initialize the variable parts of a trampoline.
2470 FNADDR is an RTX for the address of the function's pure code.
2471 CXT is an RTX for the static chain value for the function.
2472 On Nios II, we handle this by a library call. */
2474 nios2_trampoline_init (rtx m_tramp
, tree fndecl
, rtx cxt
)
2476 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
2477 rtx ctx_reg
= force_reg (Pmode
, cxt
);
2478 rtx addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
2480 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__trampoline_setup"),
2481 LCT_NORMAL
, VOIDmode
, 3, addr
, Pmode
, fnaddr
, Pmode
,
2485 /* Implement TARGET_FUNCTION_VALUE. */
2487 nios2_function_value (const_tree ret_type
, const_tree fn ATTRIBUTE_UNUSED
,
2488 bool outgoing ATTRIBUTE_UNUSED
)
2490 return gen_rtx_REG (TYPE_MODE (ret_type
), FIRST_RETVAL_REGNO
);
2493 /* Implement TARGET_LIBCALL_VALUE. */
2495 nios2_libcall_value (machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
2497 return gen_rtx_REG (mode
, FIRST_RETVAL_REGNO
);
2500 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
2502 nios2_function_value_regno_p (const unsigned int regno
)
2504 return regno
== FIRST_RETVAL_REGNO
;
2507 /* Implement TARGET_RETURN_IN_MEMORY. */
2509 nios2_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
2511 return (int_size_in_bytes (type
) > (2 * UNITS_PER_WORD
)
2512 || int_size_in_bytes (type
) == -1);
2515 /* TODO: It may be possible to eliminate the copyback and implement
2518 nios2_setup_incoming_varargs (cumulative_args_t cum_v
,
2519 machine_mode mode
, tree type
,
2520 int *pretend_size
, int second_time
)
2522 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2523 CUMULATIVE_ARGS local_cum
;
2524 cumulative_args_t local_cum_v
= pack_cumulative_args (&local_cum
);
2529 nios2_function_arg_advance (local_cum_v
, mode
, type
, 1);
2531 regs_to_push
= NUM_ARG_REGS
- local_cum
.regs_used
;
2533 if (!second_time
&& regs_to_push
> 0)
2535 rtx ptr
= virtual_incoming_args_rtx
;
2536 rtx mem
= gen_rtx_MEM (BLKmode
, ptr
);
2537 emit_insn (gen_blockage ());
2538 move_block_from_reg (local_cum
.regs_used
+ FIRST_ARG_REGNO
, mem
,
2540 emit_insn (gen_blockage ());
2543 pret_size
= regs_to_push
* UNITS_PER_WORD
;
2545 *pretend_size
= pret_size
;
2550 /* Init FPU builtins. */
2552 nios2_init_fpu_builtins (int start_code
)
2555 char builtin_name
[64] = "__builtin_custom_";
2556 unsigned int i
, n
= strlen ("__builtin_custom_");
2558 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
2560 snprintf (builtin_name
+ n
, sizeof (builtin_name
) - n
,
2561 "%s", N2FPU_NAME (i
));
2563 add_builtin_function (builtin_name
, nios2_ftype (N2FPU_FTCODE (i
)),
2564 start_code
+ i
, BUILT_IN_MD
, NULL
, NULL_TREE
);
2565 nios2_register_builtin_fndecl (start_code
+ i
, fndecl
);
2569 /* Helper function for expanding FPU builtins. */
2571 nios2_expand_fpu_builtin (tree exp
, unsigned int code
, rtx target
)
2573 struct expand_operand ops
[MAX_RECOG_OPERANDS
];
2574 enum insn_code icode
= N2FPU_ICODE (code
);
2575 int nargs
, argno
, opno
= 0;
2576 int num_operands
= N2FPU (code
).num_operands
;
2577 machine_mode dst_mode
= TYPE_MODE (TREE_TYPE (exp
));
2578 bool has_target_p
= (dst_mode
!= VOIDmode
);
2580 if (N2FPU_N (code
) < 0)
2581 fatal_error (input_location
,
2582 "Cannot call %<__builtin_custom_%s%> without specifying switch"
2583 " %<-mcustom-%s%>", N2FPU_NAME (code
), N2FPU_NAME (code
));
2585 create_output_operand (&ops
[opno
++], target
, dst_mode
);
2587 /* Subtract away the count of the VOID return, mainly for fwrx/fwry. */
2589 nargs
= call_expr_nargs (exp
);
2590 for (argno
= 0; argno
< nargs
; argno
++)
2592 tree arg
= CALL_EXPR_ARG (exp
, argno
);
2593 create_input_operand (&ops
[opno
++], expand_normal (arg
),
2594 TYPE_MODE (TREE_TYPE (arg
)));
2596 if (!maybe_expand_insn (icode
, num_operands
, ops
))
2598 error ("invalid argument to built-in function");
2599 return has_target_p
? gen_reg_rtx (ops
[0].mode
) : const0_rtx
;
2601 return has_target_p
? ops
[0].value
: const0_rtx
;
2604 /* Nios II has custom instruction built-in functions of the forms:
2607 __builtin_custom_nXX
2609 __builtin_custom_XnX
2610 __builtin_custom_XnXX
2612 where each X could be either 'i' (int), 'f' (float), or 'p' (void*).
2613 Therefore with 0-1 return values, and 0-2 arguments, we have a
2614 total of (3 + 1) * (1 + 3 + 9) == 52 custom builtin functions.
2616 #define NUM_CUSTOM_BUILTINS ((3 + 1) * (1 + 3 + 9))
2617 static char custom_builtin_name
[NUM_CUSTOM_BUILTINS
][5];
2620 nios2_init_custom_builtins (int start_code
)
2622 tree builtin_ftype
, ret_type
, fndecl
;
2623 char builtin_name
[32] = "__builtin_custom_";
2624 int n
= strlen ("__builtin_custom_");
2625 int builtin_code
= 0;
2626 int lhs
, rhs1
, rhs2
;
2628 struct { tree type
; const char *c
; } op
[4];
2629 /* z */ op
[0].c
= ""; op
[0].type
= NULL_TREE
;
2630 /* f */ op
[1].c
= "f"; op
[1].type
= float_type_node
;
2631 /* i */ op
[2].c
= "i"; op
[2].type
= integer_type_node
;
2632 /* p */ op
[3].c
= "p"; op
[3].type
= ptr_type_node
;
2634 /* We enumerate through the possible operand types to create all the
2635 __builtin_custom_XnXX function tree types. Note that these may slightly
2636 overlap with the function types created for other fixed builtins. */
2638 for (lhs
= 0; lhs
< 4; lhs
++)
2639 for (rhs1
= 0; rhs1
< 4; rhs1
++)
2640 for (rhs2
= 0; rhs2
< 4; rhs2
++)
2642 if (rhs1
== 0 && rhs2
!= 0)
2644 ret_type
= (op
[lhs
].type
? op
[lhs
].type
: void_type_node
);
2646 = build_function_type_list (ret_type
, integer_type_node
,
2647 op
[rhs1
].type
, op
[rhs2
].type
,
2649 snprintf (builtin_name
+ n
, 32 - n
, "%sn%s%s",
2650 op
[lhs
].c
, op
[rhs1
].c
, op
[rhs2
].c
);
2651 /* Save copy of parameter string into custom_builtin_name[]. */
2652 strncpy (custom_builtin_name
[builtin_code
], builtin_name
+ n
, 5);
2654 add_builtin_function (builtin_name
, builtin_ftype
,
2655 start_code
+ builtin_code
,
2656 BUILT_IN_MD
, NULL
, NULL_TREE
);
2657 nios2_register_builtin_fndecl (start_code
+ builtin_code
, fndecl
);
2662 /* Helper function for expanding custom builtins. */
2664 nios2_expand_custom_builtin (tree exp
, unsigned int index
, rtx target
)
2666 bool has_target_p
= (TREE_TYPE (exp
) != void_type_node
);
2667 machine_mode tmode
= VOIDmode
;
2669 rtx value
, insn
, unspec_args
[3];
2675 tmode
= TYPE_MODE (TREE_TYPE (exp
));
2676 if (!target
|| GET_MODE (target
) != tmode
2678 target
= gen_reg_rtx (tmode
);
2681 nargs
= call_expr_nargs (exp
);
2682 for (argno
= 0; argno
< nargs
; argno
++)
2684 arg
= CALL_EXPR_ARG (exp
, argno
);
2685 value
= expand_normal (arg
);
2686 unspec_args
[argno
] = value
;
2689 if (!custom_insn_opcode (value
, VOIDmode
))
2690 error ("custom instruction opcode must be compile time "
2691 "constant in the range 0-255 for __builtin_custom_%s",
2692 custom_builtin_name
[index
]);
2695 /* For other arguments, force into a register. */
2696 unspec_args
[argno
] = force_reg (TYPE_MODE (TREE_TYPE (arg
)),
2697 unspec_args
[argno
]);
2699 /* Fill remaining unspec operands with zero. */
2700 for (; argno
< 3; argno
++)
2701 unspec_args
[argno
] = const0_rtx
;
2703 insn
= (has_target_p
2704 ? gen_rtx_SET (target
,
2705 gen_rtx_UNSPEC_VOLATILE (tmode
,
2706 gen_rtvec_v (3, unspec_args
),
2707 UNSPECV_CUSTOM_XNXX
))
2708 : gen_rtx_UNSPEC_VOLATILE (VOIDmode
, gen_rtvec_v (3, unspec_args
),
2709 UNSPECV_CUSTOM_NXX
));
2711 return has_target_p
? target
: const0_rtx
;
2717 /* Main definition of built-in functions. Nios II has a small number of fixed
2718 builtins, plus a large number of FPU insn builtins, and builtins for
2719 generating custom instructions. */
2721 struct nios2_builtin_desc
2723 enum insn_code icode
;
2724 enum nios2_ftcode ftype
;
2728 #define N2_BUILTINS \
2729 N2_BUILTIN_DEF (sync, N2_FTYPE_VOID_VOID) \
2730 N2_BUILTIN_DEF (ldbio, N2_FTYPE_SI_CVPTR) \
2731 N2_BUILTIN_DEF (ldbuio, N2_FTYPE_UI_CVPTR) \
2732 N2_BUILTIN_DEF (ldhio, N2_FTYPE_SI_CVPTR) \
2733 N2_BUILTIN_DEF (ldhuio, N2_FTYPE_UI_CVPTR) \
2734 N2_BUILTIN_DEF (ldwio, N2_FTYPE_SI_CVPTR) \
2735 N2_BUILTIN_DEF (stbio, N2_FTYPE_VOID_VPTR_SI) \
2736 N2_BUILTIN_DEF (sthio, N2_FTYPE_VOID_VPTR_SI) \
2737 N2_BUILTIN_DEF (stwio, N2_FTYPE_VOID_VPTR_SI) \
2738 N2_BUILTIN_DEF (rdctl, N2_FTYPE_SI_SI) \
2739 N2_BUILTIN_DEF (wrctl, N2_FTYPE_VOID_SI_SI)
2741 enum nios2_builtin_code
{
2742 #define N2_BUILTIN_DEF(name, ftype) NIOS2_BUILTIN_ ## name,
2744 #undef N2_BUILTIN_DEF
2745 NUM_FIXED_NIOS2_BUILTINS
2748 static const struct nios2_builtin_desc nios2_builtins
[] = {
2749 #define N2_BUILTIN_DEF(name, ftype) \
2750 { CODE_FOR_ ## name, ftype, "__builtin_" #name },
2752 #undef N2_BUILTIN_DEF
2755 /* Start/ends of FPU/custom insn builtin index ranges. */
2756 static unsigned int nios2_fpu_builtin_base
;
2757 static unsigned int nios2_custom_builtin_base
;
2758 static unsigned int nios2_custom_builtin_end
;
2760 /* Implement TARGET_INIT_BUILTINS. */
2762 nios2_init_builtins (void)
2766 /* Initialize fixed builtins. */
2767 for (i
= 0; i
< ARRAY_SIZE (nios2_builtins
); i
++)
2769 const struct nios2_builtin_desc
*d
= &nios2_builtins
[i
];
2771 add_builtin_function (d
->name
, nios2_ftype (d
->ftype
), i
,
2772 BUILT_IN_MD
, NULL
, NULL
);
2773 nios2_register_builtin_fndecl (i
, fndecl
);
2776 /* Initialize FPU builtins. */
2777 nios2_fpu_builtin_base
= ARRAY_SIZE (nios2_builtins
);
2778 nios2_init_fpu_builtins (nios2_fpu_builtin_base
);
2780 /* Initialize custom insn builtins. */
2781 nios2_custom_builtin_base
2782 = nios2_fpu_builtin_base
+ ARRAY_SIZE (nios2_fpu_insn
);
2783 nios2_custom_builtin_end
2784 = nios2_custom_builtin_base
+ NUM_CUSTOM_BUILTINS
;
2785 nios2_init_custom_builtins (nios2_custom_builtin_base
);
2788 /* Array of fndecls for TARGET_BUILTIN_DECL. */
2789 #define NIOS2_NUM_BUILTINS \
2790 (ARRAY_SIZE (nios2_builtins) + ARRAY_SIZE (nios2_fpu_insn) + NUM_CUSTOM_BUILTINS)
2791 static GTY(()) tree nios2_builtin_decls
[NIOS2_NUM_BUILTINS
];
2794 nios2_register_builtin_fndecl (unsigned code
, tree fndecl
)
2796 nios2_builtin_decls
[code
] = fndecl
;
2799 /* Implement TARGET_BUILTIN_DECL. */
2801 nios2_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
2803 gcc_assert (nios2_custom_builtin_end
== ARRAY_SIZE (nios2_builtin_decls
));
2805 if (code
>= nios2_custom_builtin_end
)
2806 return error_mark_node
;
2808 if (code
>= nios2_fpu_builtin_base
2809 && code
< nios2_custom_builtin_base
2810 && ! N2FPU_ENABLED_P (code
- nios2_fpu_builtin_base
))
2811 return error_mark_node
;
2813 return nios2_builtin_decls
[code
];
2817 /* Low-level built-in expand routine. */
2819 nios2_expand_builtin_insn (const struct nios2_builtin_desc
*d
, int n
,
2820 struct expand_operand
*ops
, bool has_target_p
)
2822 if (maybe_expand_insn (d
->icode
, n
, ops
))
2823 return has_target_p
? ops
[0].value
: const0_rtx
;
2826 error ("invalid argument to built-in function %s", d
->name
);
2827 return has_target_p
? gen_reg_rtx (ops
[0].mode
) : const0_rtx
;
2831 /* Expand ldio/stio form load-store instruction builtins. */
2833 nios2_expand_ldstio_builtin (tree exp
, rtx target
,
2834 const struct nios2_builtin_desc
*d
)
2838 struct expand_operand ops
[MAX_RECOG_OPERANDS
];
2839 machine_mode mode
= insn_data
[d
->icode
].operand
[0].mode
;
2841 addr
= expand_normal (CALL_EXPR_ARG (exp
, 0));
2842 mem
= gen_rtx_MEM (mode
, addr
);
2844 if (insn_data
[d
->icode
].operand
[0].allows_mem
)
2847 val
= expand_normal (CALL_EXPR_ARG (exp
, 1));
2848 if (CONST_INT_P (val
))
2849 val
= force_reg (mode
, gen_int_mode (INTVAL (val
), mode
));
2850 val
= simplify_gen_subreg (mode
, val
, GET_MODE (val
), 0);
2851 create_output_operand (&ops
[0], mem
, mode
);
2852 create_input_operand (&ops
[1], val
, mode
);
2853 has_target_p
= false;
2858 create_output_operand (&ops
[0], target
, mode
);
2859 create_input_operand (&ops
[1], mem
, mode
);
2860 has_target_p
= true;
2862 return nios2_expand_builtin_insn (d
, 2, ops
, has_target_p
);
2865 /* Expand rdctl/wrctl builtins. */
2867 nios2_expand_rdwrctl_builtin (tree exp
, rtx target
,
2868 const struct nios2_builtin_desc
*d
)
2870 bool has_target_p
= (insn_data
[d
->icode
].operand
[0].predicate
2871 == register_operand
);
2872 rtx ctlcode
= expand_normal (CALL_EXPR_ARG (exp
, 0));
2873 struct expand_operand ops
[MAX_RECOG_OPERANDS
];
2874 if (!rdwrctl_operand (ctlcode
, VOIDmode
))
2876 error ("Control register number must be in range 0-31 for %s",
2878 return has_target_p
? gen_reg_rtx (SImode
) : const0_rtx
;
2882 create_output_operand (&ops
[0], target
, SImode
);
2883 create_integer_operand (&ops
[1], INTVAL (ctlcode
));
2887 rtx val
= expand_normal (CALL_EXPR_ARG (exp
, 1));
2888 create_integer_operand (&ops
[0], INTVAL (ctlcode
));
2889 create_input_operand (&ops
[1], val
, SImode
);
2891 return nios2_expand_builtin_insn (d
, 2, ops
, has_target_p
);
2894 /* Implement TARGET_EXPAND_BUILTIN. Expand an expression EXP that calls
2895 a built-in function, with result going to TARGET if that's convenient
2896 (and in mode MODE if that's convenient).
2897 SUBTARGET may be used as the target for computing one of EXP's operands.
2898 IGNORE is nonzero if the value is to be ignored. */
2901 nios2_expand_builtin (tree exp
, rtx target
, rtx subtarget ATTRIBUTE_UNUSED
,
2902 machine_mode mode ATTRIBUTE_UNUSED
,
2903 int ignore ATTRIBUTE_UNUSED
)
2905 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
2906 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
2908 if (fcode
< nios2_fpu_builtin_base
)
2910 const struct nios2_builtin_desc
*d
= &nios2_builtins
[fcode
];
2914 case NIOS2_BUILTIN_sync
:
2915 emit_insn (gen_sync ());
2918 case NIOS2_BUILTIN_ldbio
:
2919 case NIOS2_BUILTIN_ldbuio
:
2920 case NIOS2_BUILTIN_ldhio
:
2921 case NIOS2_BUILTIN_ldhuio
:
2922 case NIOS2_BUILTIN_ldwio
:
2923 case NIOS2_BUILTIN_stbio
:
2924 case NIOS2_BUILTIN_sthio
:
2925 case NIOS2_BUILTIN_stwio
:
2926 return nios2_expand_ldstio_builtin (exp
, target
, d
);
2928 case NIOS2_BUILTIN_rdctl
:
2929 case NIOS2_BUILTIN_wrctl
:
2930 return nios2_expand_rdwrctl_builtin (exp
, target
, d
);
2936 else if (fcode
< nios2_custom_builtin_base
)
2937 /* FPU builtin range. */
2938 return nios2_expand_fpu_builtin (exp
, fcode
- nios2_fpu_builtin_base
,
2940 else if (fcode
< nios2_custom_builtin_end
)
2941 /* Custom insn builtin range. */
2942 return nios2_expand_custom_builtin (exp
, fcode
- nios2_custom_builtin_base
,
2948 /* Implement TARGET_INIT_LIBFUNCS. */
2950 nios2_init_libfuncs (void)
2952 /* For Linux, we have access to kernel support for atomic operations. */
2953 if (TARGET_LINUX_ABI
)
2954 init_sync_libfuncs (UNITS_PER_WORD
);
2959 /* Register a custom code use, and signal error if a conflict was found. */
2961 nios2_register_custom_code (unsigned int N
, enum nios2_ccs_code status
,
2964 gcc_assert (N
<= 255);
2966 if (status
== CCS_FPU
)
2968 if (custom_code_status
[N
] == CCS_FPU
&& index
!= custom_code_index
[N
])
2970 custom_code_conflict
= true;
2971 error ("switch %<-mcustom-%s%> conflicts with switch %<-mcustom-%s%>",
2972 N2FPU_NAME (custom_code_index
[N
]), N2FPU_NAME (index
));
2974 else if (custom_code_status
[N
] == CCS_BUILTIN_CALL
)
2976 custom_code_conflict
= true;
2977 error ("call to %<__builtin_custom_%s%> conflicts with switch "
2978 "%<-mcustom-%s%>", custom_builtin_name
[custom_code_index
[N
]],
2979 N2FPU_NAME (index
));
2982 else if (status
== CCS_BUILTIN_CALL
)
2984 if (custom_code_status
[N
] == CCS_FPU
)
2986 custom_code_conflict
= true;
2987 error ("call to %<__builtin_custom_%s%> conflicts with switch "
2988 "%<-mcustom-%s%>", custom_builtin_name
[index
],
2989 N2FPU_NAME (custom_code_index
[N
]));
2993 /* Note that code conflicts between different __builtin_custom_xnxx
2994 calls are not checked. */
3000 custom_code_status
[N
] = status
;
3001 custom_code_index
[N
] = index
;
3004 /* Mark a custom code as not in use. */
3006 nios2_deregister_custom_code (unsigned int N
)
3010 custom_code_status
[N
] = CCS_UNUSED
;
3011 custom_code_index
[N
] = 0;
3015 /* Target attributes can affect per-function option state, so we need to
3016 save/restore the custom code tracking info using the
3017 TARGET_OPTION_SAVE/TARGET_OPTION_RESTORE hooks. */
3020 nios2_option_save (struct cl_target_option
*ptr
,
3021 struct gcc_options
*opts ATTRIBUTE_UNUSED
)
3024 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
3025 ptr
->saved_fpu_custom_code
[i
] = N2FPU_N (i
);
3026 memcpy (ptr
->saved_custom_code_status
, custom_code_status
,
3027 sizeof (custom_code_status
));
3028 memcpy (ptr
->saved_custom_code_index
, custom_code_index
,
3029 sizeof (custom_code_index
));
3033 nios2_option_restore (struct gcc_options
*opts ATTRIBUTE_UNUSED
,
3034 struct cl_target_option
*ptr
)
3037 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
3038 N2FPU_N (i
) = ptr
->saved_fpu_custom_code
[i
];
3039 memcpy (custom_code_status
, ptr
->saved_custom_code_status
,
3040 sizeof (custom_code_status
));
3041 memcpy (custom_code_index
, ptr
->saved_custom_code_index
,
3042 sizeof (custom_code_index
));
3045 /* Inner function to process the attribute((target(...))), take an argument and
3046 set the current options from the argument. If we have a list, recursively
3047 go over the list. */
3050 nios2_valid_target_attribute_rec (tree args
)
3052 if (TREE_CODE (args
) == TREE_LIST
)
3055 for (; args
; args
= TREE_CHAIN (args
))
3056 if (TREE_VALUE (args
)
3057 && !nios2_valid_target_attribute_rec (TREE_VALUE (args
)))
3061 else if (TREE_CODE (args
) == STRING_CST
)
3063 char *argstr
= ASTRDUP (TREE_STRING_POINTER (args
));
3064 while (argstr
&& *argstr
!= '\0')
3066 bool no_opt
= false, end_p
= false;
3067 char *eq
= NULL
, *p
;
3068 while (ISSPACE (*argstr
))
3071 while (*p
!= '\0' && *p
!= ',')
3073 if (!eq
&& *p
== '=')
3083 if (!strncmp (argstr
, "no-", 3))
3088 if (!strncmp (argstr
, "custom-fpu-cfg", 14))
3093 error ("custom-fpu-cfg option does not support %<no-%>");
3098 error ("custom-fpu-cfg option requires configuration"
3102 /* Increment and skip whitespace. */
3103 while (ISSPACE (*(++eq
))) ;
3104 /* Decrement and skip to before any trailing whitespace. */
3105 while (ISSPACE (*(--end_eq
))) ;
3107 nios2_handle_custom_fpu_cfg (eq
, end_eq
+ 1, true);
3109 else if (!strncmp (argstr
, "custom-", 7))
3113 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
3114 if (!strncmp (argstr
+ 7, N2FPU_NAME (i
),
3115 strlen (N2FPU_NAME (i
))))
3127 error ("%<no-custom-%s%> does not accept arguments",
3131 /* Disable option by setting to -1. */
3132 nios2_deregister_custom_code (N2FPU_N (code
));
3133 N2FPU_N (code
) = -1;
3139 while (ISSPACE (*(++eq
))) ;
3142 error ("%<custom-%s=%> requires argument",
3146 for (t
= eq
; t
!= p
; ++t
)
3152 error ("`custom-%s=' argument requires "
3153 "numeric digits", N2FPU_NAME (code
));
3157 /* Set option to argument. */
3158 N2FPU_N (code
) = atoi (eq
);
3159 nios2_handle_custom_fpu_insn_option (code
);
3164 error ("%<custom-%s=%> is not recognised as FPU instruction",
3171 error ("%<%s%> is unknown", argstr
);
3186 /* Return a TARGET_OPTION_NODE tree of the target options listed or NULL. */
3189 nios2_valid_target_attribute_tree (tree args
)
3191 if (!nios2_valid_target_attribute_rec (args
))
3193 nios2_custom_check_insns ();
3194 return build_target_option_node (&global_options
);
3197 /* Hook to validate attribute((target("string"))). */
3200 nios2_valid_target_attribute_p (tree fndecl
, tree
ARG_UNUSED (name
),
3201 tree args
, int ARG_UNUSED (flags
))
3203 struct cl_target_option cur_target
;
3205 tree old_optimize
= build_optimization_node (&global_options
);
3206 tree new_target
, new_optimize
;
3207 tree func_optimize
= DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl
);
3209 /* If the function changed the optimization levels as well as setting target
3210 options, start with the optimizations specified. */
3211 if (func_optimize
&& func_optimize
!= old_optimize
)
3212 cl_optimization_restore (&global_options
,
3213 TREE_OPTIMIZATION (func_optimize
));
3215 /* The target attributes may also change some optimization flags, so update
3216 the optimization options if necessary. */
3217 cl_target_option_save (&cur_target
, &global_options
);
3218 new_target
= nios2_valid_target_attribute_tree (args
);
3219 new_optimize
= build_optimization_node (&global_options
);
3226 DECL_FUNCTION_SPECIFIC_TARGET (fndecl
) = new_target
;
3228 if (old_optimize
!= new_optimize
)
3229 DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl
) = new_optimize
;
3232 cl_target_option_restore (&global_options
, &cur_target
);
3234 if (old_optimize
!= new_optimize
)
3235 cl_optimization_restore (&global_options
,
3236 TREE_OPTIMIZATION (old_optimize
));
3240 /* Remember the last target of nios2_set_current_function. */
3241 static GTY(()) tree nios2_previous_fndecl
;
3243 /* Establish appropriate back-end context for processing the function
3244 FNDECL. The argument might be NULL to indicate processing at top
3245 level, outside of any function scope. */
3247 nios2_set_current_function (tree fndecl
)
3249 tree old_tree
= (nios2_previous_fndecl
3250 ? DECL_FUNCTION_SPECIFIC_TARGET (nios2_previous_fndecl
)
3253 tree new_tree
= (fndecl
3254 ? DECL_FUNCTION_SPECIFIC_TARGET (fndecl
)
3257 if (fndecl
&& fndecl
!= nios2_previous_fndecl
)
3259 nios2_previous_fndecl
= fndecl
;
3260 if (old_tree
== new_tree
)
3265 cl_target_option_restore (&global_options
,
3266 TREE_TARGET_OPTION (new_tree
));
3272 struct cl_target_option
*def
3273 = TREE_TARGET_OPTION (target_option_current_node
);
3275 cl_target_option_restore (&global_options
, def
);
3281 /* Hook to validate the current #pragma GCC target and set the FPU custom
3282 code option state. If ARGS is NULL, then POP_TARGET is used to reset
3285 nios2_pragma_target_parse (tree args
, tree pop_target
)
3290 cur_tree
= ((pop_target
)
3292 : target_option_default_node
);
3293 cl_target_option_restore (&global_options
,
3294 TREE_TARGET_OPTION (cur_tree
));
3298 cur_tree
= nios2_valid_target_attribute_tree (args
);
3303 target_option_current_node
= cur_tree
;
3307 /* Implement TARGET_MERGE_DECL_ATTRIBUTES.
3308 We are just using this hook to add some additional error checking to
3309 the default behavior. GCC does not provide a target hook for merging
3310 the target options, and only correctly handles merging empty vs non-empty
3311 option data; see merge_decls() in c-decl.c.
3312 So here we require either that at least one of the decls has empty
3313 target options, or that the target options/data be identical. */
3315 nios2_merge_decl_attributes (tree olddecl
, tree newdecl
)
3317 tree oldopts
= lookup_attribute ("target", DECL_ATTRIBUTES (olddecl
));
3318 tree newopts
= lookup_attribute ("target", DECL_ATTRIBUTES (newdecl
));
3319 if (newopts
&& oldopts
&& newopts
!= oldopts
)
3321 tree oldtree
= DECL_FUNCTION_SPECIFIC_TARGET (olddecl
);
3322 tree newtree
= DECL_FUNCTION_SPECIFIC_TARGET (newdecl
);
3323 if (oldtree
&& newtree
&& oldtree
!= newtree
)
3325 struct cl_target_option
*olddata
= TREE_TARGET_OPTION (oldtree
);
3326 struct cl_target_option
*newdata
= TREE_TARGET_OPTION (newtree
);
3327 if (olddata
!= newdata
3328 && memcmp (olddata
, newdata
, sizeof (struct cl_target_option
)))
3329 error ("%qE redeclared with conflicting %qs attributes",
3330 DECL_NAME (newdecl
), "target");
3333 return merge_attributes (DECL_ATTRIBUTES (olddecl
),
3334 DECL_ATTRIBUTES (newdecl
));
3337 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
3339 nios2_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3340 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3343 rtx this_rtx
, funexp
;
3346 /* Pretend to be a post-reload pass while generating rtl. */
3347 reload_completed
= 1;
3350 nios2_load_pic_register ();
3352 /* Mark the end of the (empty) prologue. */
3353 emit_note (NOTE_INSN_PROLOGUE_END
);
3355 /* Find the "this" pointer. If the function returns a structure,
3356 the structure return pointer is in $5. */
3357 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3358 this_rtx
= gen_rtx_REG (Pmode
, FIRST_ARG_REGNO
+ 1);
3360 this_rtx
= gen_rtx_REG (Pmode
, FIRST_ARG_REGNO
);
3362 /* Add DELTA to THIS_RTX. */
3363 nios2_emit_add_constant (this_rtx
, delta
);
3365 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
3370 tmp
= gen_rtx_REG (Pmode
, 2);
3371 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, this_rtx
));
3372 nios2_emit_add_constant (tmp
, vcall_offset
);
3373 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, tmp
));
3374 emit_insn (gen_add2_insn (this_rtx
, tmp
));
3377 /* Generate a tail call to the target function. */
3378 if (!TREE_USED (function
))
3380 assemble_external (function
);
3381 TREE_USED (function
) = 1;
3383 funexp
= XEXP (DECL_RTL (function
), 0);
3384 /* Function address needs to be constructed under PIC,
3385 provide r2 to use here. */
3386 nios2_adjust_call_address (&funexp
, gen_rtx_REG (Pmode
, 2));
3387 insn
= emit_call_insn (gen_sibcall_internal (funexp
, const0_rtx
));
3388 SIBLING_CALL_P (insn
) = 1;
3390 /* Run just enough of rest_of_compilation to get the insns emitted.
3391 There's not really enough bulk here to make other passes such as
3392 instruction scheduling worth while. Note that use_thunk calls
3393 assemble_start_function and assemble_end_function. */
3394 insn
= get_insns ();
3395 shorten_branches (insn
);
3396 final_start_function (insn
, file
, 1);
3397 final (insn
, file
, 1);
3398 final_end_function ();
3400 /* Stop pretending to be a post-reload pass. */
3401 reload_completed
= 0;
3405 /* Initialize the GCC target structure. */
3406 #undef TARGET_ASM_FUNCTION_PROLOGUE
3407 #define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue
3409 #undef TARGET_IN_SMALL_DATA_P
3410 #define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p
3412 #undef TARGET_SECTION_TYPE_FLAGS
3413 #define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags
3415 #undef TARGET_INIT_BUILTINS
3416 #define TARGET_INIT_BUILTINS nios2_init_builtins
3417 #undef TARGET_EXPAND_BUILTIN
3418 #define TARGET_EXPAND_BUILTIN nios2_expand_builtin
3419 #undef TARGET_BUILTIN_DECL
3420 #define TARGET_BUILTIN_DECL nios2_builtin_decl
3422 #undef TARGET_INIT_LIBFUNCS
3423 #define TARGET_INIT_LIBFUNCS nios2_init_libfuncs
3425 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
3426 #define TARGET_FUNCTION_OK_FOR_SIBCALL hook_bool_tree_tree_true
3428 #undef TARGET_CAN_ELIMINATE
3429 #define TARGET_CAN_ELIMINATE nios2_can_eliminate
3431 #undef TARGET_FUNCTION_ARG
3432 #define TARGET_FUNCTION_ARG nios2_function_arg
3434 #undef TARGET_FUNCTION_ARG_ADVANCE
3435 #define TARGET_FUNCTION_ARG_ADVANCE nios2_function_arg_advance
3437 #undef TARGET_ARG_PARTIAL_BYTES
3438 #define TARGET_ARG_PARTIAL_BYTES nios2_arg_partial_bytes
3440 #undef TARGET_TRAMPOLINE_INIT
3441 #define TARGET_TRAMPOLINE_INIT nios2_trampoline_init
3443 #undef TARGET_FUNCTION_VALUE
3444 #define TARGET_FUNCTION_VALUE nios2_function_value
3446 #undef TARGET_LIBCALL_VALUE
3447 #define TARGET_LIBCALL_VALUE nios2_libcall_value
3449 #undef TARGET_FUNCTION_VALUE_REGNO_P
3450 #define TARGET_FUNCTION_VALUE_REGNO_P nios2_function_value_regno_p
3452 #undef TARGET_RETURN_IN_MEMORY
3453 #define TARGET_RETURN_IN_MEMORY nios2_return_in_memory
3455 #undef TARGET_PROMOTE_PROTOTYPES
3456 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
3458 #undef TARGET_SETUP_INCOMING_VARARGS
3459 #define TARGET_SETUP_INCOMING_VARARGS nios2_setup_incoming_varargs
3461 #undef TARGET_MUST_PASS_IN_STACK
3462 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
3464 #undef TARGET_LEGITIMATE_CONSTANT_P
3465 #define TARGET_LEGITIMATE_CONSTANT_P nios2_legitimate_constant_p
3467 #undef TARGET_LEGITIMIZE_ADDRESS
3468 #define TARGET_LEGITIMIZE_ADDRESS nios2_legitimize_address
3470 #undef TARGET_DELEGITIMIZE_ADDRESS
3471 #define TARGET_DELEGITIMIZE_ADDRESS nios2_delegitimize_address
3473 #undef TARGET_LEGITIMATE_ADDRESS_P
3474 #define TARGET_LEGITIMATE_ADDRESS_P nios2_legitimate_address_p
3476 #undef TARGET_PREFERRED_RELOAD_CLASS
3477 #define TARGET_PREFERRED_RELOAD_CLASS nios2_preferred_reload_class
3479 #undef TARGET_RTX_COSTS
3480 #define TARGET_RTX_COSTS nios2_rtx_costs
3482 #undef TARGET_HAVE_TLS
3483 #define TARGET_HAVE_TLS TARGET_LINUX_ABI
3485 #undef TARGET_CANNOT_FORCE_CONST_MEM
3486 #define TARGET_CANNOT_FORCE_CONST_MEM nios2_cannot_force_const_mem
3488 #undef TARGET_ASM_OUTPUT_DWARF_DTPREL
3489 #define TARGET_ASM_OUTPUT_DWARF_DTPREL nios2_output_dwarf_dtprel
3491 #undef TARGET_PRINT_OPERAND
3492 #define TARGET_PRINT_OPERAND nios2_print_operand
3494 #undef TARGET_PRINT_OPERAND_ADDRESS
3495 #define TARGET_PRINT_OPERAND_ADDRESS nios2_print_operand_address
3497 #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
3498 #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA nios2_output_addr_const_extra
3500 #undef TARGET_ASM_FILE_END
3501 #define TARGET_ASM_FILE_END nios2_asm_file_end
3503 #undef TARGET_OPTION_OVERRIDE
3504 #define TARGET_OPTION_OVERRIDE nios2_option_override
3506 #undef TARGET_OPTION_SAVE
3507 #define TARGET_OPTION_SAVE nios2_option_save
3509 #undef TARGET_OPTION_RESTORE
3510 #define TARGET_OPTION_RESTORE nios2_option_restore
3512 #undef TARGET_SET_CURRENT_FUNCTION
3513 #define TARGET_SET_CURRENT_FUNCTION nios2_set_current_function
3515 #undef TARGET_OPTION_VALID_ATTRIBUTE_P
3516 #define TARGET_OPTION_VALID_ATTRIBUTE_P nios2_valid_target_attribute_p
3518 #undef TARGET_OPTION_PRAGMA_PARSE
3519 #define TARGET_OPTION_PRAGMA_PARSE nios2_pragma_target_parse
3521 #undef TARGET_MERGE_DECL_ATTRIBUTES
3522 #define TARGET_MERGE_DECL_ATTRIBUTES nios2_merge_decl_attributes
3524 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3525 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
3526 hook_bool_const_tree_hwi_hwi_const_tree_true
3528 #undef TARGET_ASM_OUTPUT_MI_THUNK
3529 #define TARGET_ASM_OUTPUT_MI_THUNK nios2_asm_output_mi_thunk
3531 struct gcc_target targetm
= TARGET_INITIALIZER
;
3533 #include "gt-nios2.h"