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 "double-int.h"
38 #include "fold-const.h"
40 #include "hard-reg-set.h"
41 #include "insn-config.h"
42 #include "conditions.h"
44 #include "insn-attr.h"
49 #include "statistics.h"
51 #include "fixed-value.h"
60 #include "insn-codes.h"
64 #include "dominance.h"
70 #include "cfgcleanup.h"
71 #include "basic-block.h"
72 #include "diagnostic-core.h"
75 #include "target-def.h"
77 #include "langhooks.h"
81 #include "stor-layout.h"
84 /* Forward function declarations. */
85 static bool prologue_saved_reg_p (unsigned);
86 static void nios2_load_pic_register (void);
87 static void nios2_register_custom_code (unsigned int, enum nios2_ccs_code
, int);
88 static const char *nios2_unspec_reloc_name (int);
89 static void nios2_register_builtin_fndecl (unsigned, tree
);
91 /* Threshold for data being put into the small data/bss area, instead
92 of the normal data area (references to the small data/bss area take
93 1 instruction, and use the global pointer, references to the normal
94 data area takes 2 instructions). */
95 unsigned HOST_WIDE_INT nios2_section_threshold
= NIOS2_DEFAULT_GVALUE
;
97 struct GTY (()) machine_function
99 /* Current frame information, to be filled in by nios2_compute_frame_layout
100 with register save masks, and offsets for the current function. */
102 /* Mask of registers to save. */
103 unsigned int save_mask
;
104 /* Number of bytes that the entire frame takes up. */
106 /* Number of bytes that variables take up. */
108 /* Number of bytes that outgoing arguments take up. */
110 /* Number of bytes needed to store registers in frame. */
112 /* Offset from new stack pointer to store registers. */
113 int save_regs_offset
;
114 /* Offset from save_regs_offset to store frame pointer register. */
116 /* != 0 if frame layout already calculated. */
120 /* State to track the assignment of custom codes to FPU/custom builtins. */
121 static enum nios2_ccs_code custom_code_status
[256];
122 static int custom_code_index
[256];
123 /* Set to true if any conflicts (re-use of a code between 0-255) are found. */
124 static bool custom_code_conflict
= false;
127 /* Definition of builtin function types for nios2. */
131 N2_FTYPE(1, (VOID)) \
132 N2_FTYPE(2, (DF, DF)) \
133 N2_FTYPE(3, (DF, DF, DF)) \
134 N2_FTYPE(2, (DF, SF)) \
135 N2_FTYPE(2, (DF, SI)) \
136 N2_FTYPE(2, (DF, UI)) \
137 N2_FTYPE(2, (SF, DF)) \
138 N2_FTYPE(2, (SF, SF)) \
139 N2_FTYPE(3, (SF, SF, SF)) \
140 N2_FTYPE(2, (SF, SI)) \
141 N2_FTYPE(2, (SF, UI)) \
142 N2_FTYPE(2, (SI, CVPTR)) \
143 N2_FTYPE(2, (SI, DF)) \
144 N2_FTYPE(3, (SI, DF, DF)) \
145 N2_FTYPE(2, (SI, SF)) \
146 N2_FTYPE(3, (SI, SF, SF)) \
147 N2_FTYPE(2, (SI, SI)) \
148 N2_FTYPE(2, (UI, CVPTR)) \
149 N2_FTYPE(2, (UI, DF)) \
150 N2_FTYPE(2, (UI, SF)) \
151 N2_FTYPE(2, (VOID, DF)) \
152 N2_FTYPE(2, (VOID, SF)) \
153 N2_FTYPE(3, (VOID, SI, SI)) \
154 N2_FTYPE(3, (VOID, VPTR, SI))
156 #define N2_FTYPE_OP1(R) N2_FTYPE_ ## R ## _VOID
157 #define N2_FTYPE_OP2(R, A1) N2_FTYPE_ ## R ## _ ## A1
158 #define N2_FTYPE_OP3(R, A1, A2) N2_FTYPE_ ## R ## _ ## A1 ## _ ## A2
160 /* Expand ftcode enumeration. */
162 #define N2_FTYPE(N,ARGS) N2_FTYPE_OP ## N ARGS,
168 /* Return the tree function type, based on the ftcode. */
170 nios2_ftype (enum nios2_ftcode ftcode
)
172 static tree types
[(int) N2_FTYPE_MAX
];
174 tree N2_TYPE_SF
= float_type_node
;
175 tree N2_TYPE_DF
= double_type_node
;
176 tree N2_TYPE_SI
= integer_type_node
;
177 tree N2_TYPE_UI
= unsigned_type_node
;
178 tree N2_TYPE_VOID
= void_type_node
;
180 static const_tree N2_TYPE_CVPTR
, N2_TYPE_VPTR
;
183 /* const volatile void *. */
185 = build_pointer_type (build_qualified_type (void_type_node
,
187 | TYPE_QUAL_VOLATILE
)));
188 /* volatile void *. */
190 = build_pointer_type (build_qualified_type (void_type_node
,
191 TYPE_QUAL_VOLATILE
));
193 if (types
[(int) ftcode
] == NULL_TREE
)
196 #define N2_FTYPE_ARGS1(R) N2_TYPE_ ## R
197 #define N2_FTYPE_ARGS2(R,A1) N2_TYPE_ ## R, N2_TYPE_ ## A1
198 #define N2_FTYPE_ARGS3(R,A1,A2) N2_TYPE_ ## R, N2_TYPE_ ## A1, N2_TYPE_ ## A2
199 #define N2_FTYPE(N,ARGS) \
200 case N2_FTYPE_OP ## N ARGS: \
201 types[(int) ftcode] \
202 = build_function_type_list (N2_FTYPE_ARGS ## N ARGS, NULL_TREE); \
206 default: gcc_unreachable ();
208 return types
[(int) ftcode
];
212 /* Definition of FPU instruction descriptions. */
214 struct nios2_fpu_insn_info
217 int num_operands
, *optvar
;
220 #define N2F_DFREQ 0x2
221 #define N2F_UNSAFE 0x4
222 #define N2F_FINITE 0x8
223 #define N2F_NO_ERRNO 0x10
225 enum insn_code icode
;
226 enum nios2_ftcode ftcode
;
229 /* Base macro for defining FPU instructions. */
230 #define N2FPU_INSN_DEF_BASE(insn, nop, flags, icode, args) \
231 { #insn, nop, &nios2_custom_ ## insn, OPT_mcustom_##insn##_, \
232 OPT_mno_custom_##insn, flags, CODE_FOR_ ## icode, \
233 N2_FTYPE_OP ## nop args }
235 /* Arithmetic and math functions; 2 or 3 operand FP operations. */
236 #define N2FPU_OP2(mode) (mode, mode)
237 #define N2FPU_OP3(mode) (mode, mode, mode)
238 #define N2FPU_INSN_DEF(code, icode, nop, flags, m, M) \
239 N2FPU_INSN_DEF_BASE (f ## code ## m, nop, flags, \
240 icode ## m ## f ## nop, N2FPU_OP ## nop (M ## F))
241 #define N2FPU_INSN_SF(code, nop, flags) \
242 N2FPU_INSN_DEF (code, code, nop, flags, s, S)
243 #define N2FPU_INSN_DF(code, nop, flags) \
244 N2FPU_INSN_DEF (code, code, nop, flags | N2F_DF, d, D)
246 /* Compare instructions, 3 operand FP operation with a SI result. */
247 #define N2FPU_CMP_DEF(code, flags, m, M) \
248 N2FPU_INSN_DEF_BASE (fcmp ## code ## m, 3, flags, \
249 nios2_s ## code ## m ## f, (SI, M ## F, M ## F))
250 #define N2FPU_CMP_SF(code) N2FPU_CMP_DEF (code, 0, s, S)
251 #define N2FPU_CMP_DF(code) N2FPU_CMP_DEF (code, N2F_DF, d, D)
253 /* The order of definition needs to be maintained consistent with
254 enum n2fpu_code in nios2-opts.h. */
255 struct nios2_fpu_insn_info nios2_fpu_insn
[] =
257 /* Single precision instructions. */
258 N2FPU_INSN_SF (add
, 3, 0),
259 N2FPU_INSN_SF (sub
, 3, 0),
260 N2FPU_INSN_SF (mul
, 3, 0),
261 N2FPU_INSN_SF (div
, 3, 0),
262 /* Due to textual difference between min/max and smin/smax. */
263 N2FPU_INSN_DEF (min
, smin
, 3, N2F_FINITE
, s
, S
),
264 N2FPU_INSN_DEF (max
, smax
, 3, N2F_FINITE
, s
, S
),
265 N2FPU_INSN_SF (neg
, 2, 0),
266 N2FPU_INSN_SF (abs
, 2, 0),
267 N2FPU_INSN_SF (sqrt
, 2, 0),
268 N2FPU_INSN_SF (sin
, 2, N2F_UNSAFE
),
269 N2FPU_INSN_SF (cos
, 2, N2F_UNSAFE
),
270 N2FPU_INSN_SF (tan
, 2, N2F_UNSAFE
),
271 N2FPU_INSN_SF (atan
, 2, N2F_UNSAFE
),
272 N2FPU_INSN_SF (exp
, 2, N2F_UNSAFE
),
273 N2FPU_INSN_SF (log
, 2, N2F_UNSAFE
),
274 /* Single precision compares. */
275 N2FPU_CMP_SF (eq
), N2FPU_CMP_SF (ne
),
276 N2FPU_CMP_SF (lt
), N2FPU_CMP_SF (le
),
277 N2FPU_CMP_SF (gt
), N2FPU_CMP_SF (ge
),
279 /* Double precision instructions. */
280 N2FPU_INSN_DF (add
, 3, 0),
281 N2FPU_INSN_DF (sub
, 3, 0),
282 N2FPU_INSN_DF (mul
, 3, 0),
283 N2FPU_INSN_DF (div
, 3, 0),
284 /* Due to textual difference between min/max and smin/smax. */
285 N2FPU_INSN_DEF (min
, smin
, 3, N2F_FINITE
, d
, D
),
286 N2FPU_INSN_DEF (max
, smax
, 3, N2F_FINITE
, d
, D
),
287 N2FPU_INSN_DF (neg
, 2, 0),
288 N2FPU_INSN_DF (abs
, 2, 0),
289 N2FPU_INSN_DF (sqrt
, 2, 0),
290 N2FPU_INSN_DF (sin
, 2, N2F_UNSAFE
),
291 N2FPU_INSN_DF (cos
, 2, N2F_UNSAFE
),
292 N2FPU_INSN_DF (tan
, 2, N2F_UNSAFE
),
293 N2FPU_INSN_DF (atan
, 2, N2F_UNSAFE
),
294 N2FPU_INSN_DF (exp
, 2, N2F_UNSAFE
),
295 N2FPU_INSN_DF (log
, 2, N2F_UNSAFE
),
296 /* Double precision compares. */
297 N2FPU_CMP_DF (eq
), N2FPU_CMP_DF (ne
),
298 N2FPU_CMP_DF (lt
), N2FPU_CMP_DF (le
),
299 N2FPU_CMP_DF (gt
), N2FPU_CMP_DF (ge
),
301 /* Conversion instructions. */
302 N2FPU_INSN_DEF_BASE (floatis
, 2, 0, floatsisf2
, (SF
, SI
)),
303 N2FPU_INSN_DEF_BASE (floatus
, 2, 0, floatunssisf2
, (SF
, UI
)),
304 N2FPU_INSN_DEF_BASE (floatid
, 2, 0, floatsidf2
, (DF
, SI
)),
305 N2FPU_INSN_DEF_BASE (floatud
, 2, 0, floatunssidf2
, (DF
, UI
)),
306 N2FPU_INSN_DEF_BASE (round
, 2, N2F_NO_ERRNO
, lroundsfsi2
, (SI
, SF
)),
307 N2FPU_INSN_DEF_BASE (fixsi
, 2, 0, fix_truncsfsi2
, (SI
, SF
)),
308 N2FPU_INSN_DEF_BASE (fixsu
, 2, 0, fixuns_truncsfsi2
, (UI
, SF
)),
309 N2FPU_INSN_DEF_BASE (fixdi
, 2, 0, fix_truncdfsi2
, (SI
, DF
)),
310 N2FPU_INSN_DEF_BASE (fixdu
, 2, 0, fixuns_truncdfsi2
, (UI
, DF
)),
311 N2FPU_INSN_DEF_BASE (fextsd
, 2, 0, extendsfdf2
, (DF
, SF
)),
312 N2FPU_INSN_DEF_BASE (ftruncds
, 2, 0, truncdfsf2
, (SF
, DF
)),
314 /* X, Y access instructions. */
315 N2FPU_INSN_DEF_BASE (fwrx
, 2, N2F_DFREQ
, nios2_fwrx
, (VOID
, DF
)),
316 N2FPU_INSN_DEF_BASE (fwry
, 2, N2F_DFREQ
, nios2_fwry
, (VOID
, SF
)),
317 N2FPU_INSN_DEF_BASE (frdxlo
, 1, N2F_DFREQ
, nios2_frdxlo
, (SF
)),
318 N2FPU_INSN_DEF_BASE (frdxhi
, 1, N2F_DFREQ
, nios2_frdxhi
, (SF
)),
319 N2FPU_INSN_DEF_BASE (frdy
, 1, N2F_DFREQ
, nios2_frdy
, (SF
))
322 /* Some macros for ease of access. */
323 #define N2FPU(code) nios2_fpu_insn[(int) code]
324 #define N2FPU_ENABLED_P(code) (N2FPU_N(code) >= 0)
325 #define N2FPU_N(code) (*N2FPU(code).optvar)
326 #define N2FPU_NAME(code) (N2FPU(code).name)
327 #define N2FPU_ICODE(code) (N2FPU(code).icode)
328 #define N2FPU_FTCODE(code) (N2FPU(code).ftcode)
329 #define N2FPU_FINITE_P(code) (N2FPU(code).flags & N2F_FINITE)
330 #define N2FPU_UNSAFE_P(code) (N2FPU(code).flags & N2F_UNSAFE)
331 #define N2FPU_NO_ERRNO_P(code) (N2FPU(code).flags & N2F_NO_ERRNO)
332 #define N2FPU_DOUBLE_P(code) (N2FPU(code).flags & N2F_DF)
333 #define N2FPU_DOUBLE_REQUIRED_P(code) (N2FPU(code).flags & N2F_DFREQ)
335 /* Same as above, but for cases where using only the op part is shorter. */
336 #define N2FPU_OP(op) N2FPU(n2fpu_ ## op)
337 #define N2FPU_OP_NAME(op) N2FPU_NAME(n2fpu_ ## op)
338 #define N2FPU_OP_ENABLED_P(op) N2FPU_ENABLED_P(n2fpu_ ## op)
340 /* Export the FPU insn enabled predicate to nios2.md. */
342 nios2_fpu_insn_enabled (enum n2fpu_code code
)
344 return N2FPU_ENABLED_P (code
);
347 /* Return true if COND comparison for mode MODE is enabled under current
351 nios2_fpu_compare_enabled (enum rtx_code cond
, machine_mode mode
)
356 case EQ
: return N2FPU_OP_ENABLED_P (fcmpeqs
);
357 case NE
: return N2FPU_OP_ENABLED_P (fcmpnes
);
358 case GT
: return N2FPU_OP_ENABLED_P (fcmpgts
);
359 case GE
: return N2FPU_OP_ENABLED_P (fcmpges
);
360 case LT
: return N2FPU_OP_ENABLED_P (fcmplts
);
361 case LE
: return N2FPU_OP_ENABLED_P (fcmples
);
364 else if (mode
== DFmode
)
367 case EQ
: return N2FPU_OP_ENABLED_P (fcmpeqd
);
368 case NE
: return N2FPU_OP_ENABLED_P (fcmpned
);
369 case GT
: return N2FPU_OP_ENABLED_P (fcmpgtd
);
370 case GE
: return N2FPU_OP_ENABLED_P (fcmpged
);
371 case LT
: return N2FPU_OP_ENABLED_P (fcmpltd
);
372 case LE
: return N2FPU_OP_ENABLED_P (fcmpled
);
378 /* Stack layout and calling conventions. */
380 #define NIOS2_STACK_ALIGN(LOC) \
381 (((LOC) + ((PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) - 1)) \
382 & ~((PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) - 1))
384 /* Return the bytes needed to compute the frame pointer from the current
387 nios2_compute_frame_layout (void)
390 unsigned int save_mask
= 0;
396 if (cfun
->machine
->initialized
)
397 return cfun
->machine
->total_size
;
399 var_size
= NIOS2_STACK_ALIGN (get_frame_size ());
400 out_args_size
= NIOS2_STACK_ALIGN (crtl
->outgoing_args_size
);
401 total_size
= var_size
+ out_args_size
;
403 /* Calculate space needed for gp registers. */
405 for (regno
= 0; regno
<= LAST_GP_REG
; regno
++)
406 if (prologue_saved_reg_p (regno
))
408 save_mask
|= 1 << regno
;
412 /* If we call eh_return, we need to save the EH data registers. */
413 if (crtl
->calls_eh_return
)
418 for (i
= 0; (r
= EH_RETURN_DATA_REGNO (i
)) != INVALID_REGNUM
; i
++)
419 if (!(save_mask
& (1 << r
)))
426 cfun
->machine
->fp_save_offset
= 0;
427 if (save_mask
& (1 << HARD_FRAME_POINTER_REGNUM
))
429 int fp_save_offset
= 0;
430 for (regno
= 0; regno
< HARD_FRAME_POINTER_REGNUM
; regno
++)
431 if (save_mask
& (1 << regno
))
434 cfun
->machine
->fp_save_offset
= fp_save_offset
;
437 save_reg_size
= NIOS2_STACK_ALIGN (save_reg_size
);
438 total_size
+= save_reg_size
;
439 total_size
+= NIOS2_STACK_ALIGN (crtl
->args
.pretend_args_size
);
441 /* Save other computed information. */
442 cfun
->machine
->save_mask
= save_mask
;
443 cfun
->machine
->total_size
= total_size
;
444 cfun
->machine
->var_size
= var_size
;
445 cfun
->machine
->args_size
= out_args_size
;
446 cfun
->machine
->save_reg_size
= save_reg_size
;
447 cfun
->machine
->initialized
= reload_completed
;
448 cfun
->machine
->save_regs_offset
= out_args_size
+ var_size
;
453 /* Generate save/restore of register REGNO at SP + OFFSET. Used by the
454 prologue/epilogue expand routines. */
456 save_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 (gen_frame_mem (Pmode
, addr
), reg
);
462 RTX_FRAME_RELATED_P (insn
) = 1;
466 restore_reg (int regno
, unsigned offset
)
468 rtx reg
= gen_rtx_REG (SImode
, regno
);
469 rtx addr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
470 gen_int_mode (offset
, Pmode
));
471 rtx insn
= emit_move_insn (reg
, gen_frame_mem (Pmode
, addr
));
472 /* Tag epilogue unwind note. */
473 add_reg_note (insn
, REG_CFA_RESTORE
, reg
);
474 RTX_FRAME_RELATED_P (insn
) = 1;
477 /* Emit conditional trap for checking stack limit. */
479 nios2_emit_stack_limit_check (void)
481 if (REG_P (stack_limit_rtx
))
482 emit_insn (gen_ctrapsi4 (gen_rtx_LTU (VOIDmode
, stack_pointer_rtx
,
484 stack_pointer_rtx
, stack_limit_rtx
, GEN_INT (3)));
486 sorry ("only register based stack limit is supported");
489 /* Temp regno used inside prologue/epilogue. */
490 #define TEMP_REG_NUM 8
493 nios2_emit_add_constant (rtx reg
, HOST_WIDE_INT immed
)
496 if (SMALL_INT (immed
))
497 insn
= emit_insn (gen_add2_insn (reg
, gen_int_mode (immed
, Pmode
)));
500 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
501 emit_move_insn (tmp
, gen_int_mode (immed
, Pmode
));
502 insn
= emit_insn (gen_add2_insn (reg
, tmp
));
508 nios2_expand_prologue (void)
511 int total_frame_size
, save_offset
;
512 int sp_offset
; /* offset from base_reg to final stack value. */
513 int save_regs_base
; /* offset from base_reg to register save area. */
516 total_frame_size
= nios2_compute_frame_layout ();
518 if (flag_stack_usage_info
)
519 current_function_static_stack_size
= total_frame_size
;
521 /* Decrement the stack pointer. */
522 if (!SMALL_INT (total_frame_size
))
524 /* We need an intermediary point, this will point at the spill block. */
526 (gen_add2_insn (stack_pointer_rtx
,
527 gen_int_mode (cfun
->machine
->save_regs_offset
528 - total_frame_size
, Pmode
)));
529 RTX_FRAME_RELATED_P (insn
) = 1;
531 sp_offset
= -cfun
->machine
->save_regs_offset
;
533 else if (total_frame_size
)
535 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
,
536 gen_int_mode (-total_frame_size
,
538 RTX_FRAME_RELATED_P (insn
) = 1;
539 save_regs_base
= cfun
->machine
->save_regs_offset
;
543 save_regs_base
= sp_offset
= 0;
545 if (crtl
->limit_stack
)
546 nios2_emit_stack_limit_check ();
548 save_offset
= save_regs_base
+ cfun
->machine
->save_reg_size
;
550 for (regno
= LAST_GP_REG
; regno
> 0; regno
--)
551 if (cfun
->machine
->save_mask
& (1 << regno
))
554 save_reg (regno
, save_offset
);
557 if (frame_pointer_needed
)
559 int fp_save_offset
= save_regs_base
+ cfun
->machine
->fp_save_offset
;
560 insn
= emit_insn (gen_add3_insn (hard_frame_pointer_rtx
,
562 gen_int_mode (fp_save_offset
, Pmode
)));
563 RTX_FRAME_RELATED_P (insn
) = 1;
569 = gen_rtx_SET (stack_pointer_rtx
,
570 plus_constant (Pmode
, stack_pointer_rtx
, sp_offset
));
571 if (SMALL_INT (sp_offset
))
572 insn
= emit_insn (sp_adjust
);
575 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
576 emit_move_insn (tmp
, gen_int_mode (sp_offset
, Pmode
));
577 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
, tmp
));
578 /* Attach the sp_adjust as a note indicating what happened. */
579 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
, sp_adjust
);
581 RTX_FRAME_RELATED_P (insn
) = 1;
583 if (crtl
->limit_stack
)
584 nios2_emit_stack_limit_check ();
587 /* Load the PIC register if needed. */
588 if (crtl
->uses_pic_offset_table
)
589 nios2_load_pic_register ();
591 /* If we are profiling, make sure no instructions are scheduled before
592 the call to mcount. */
594 emit_insn (gen_blockage ());
598 nios2_expand_epilogue (bool sibcall_p
)
601 int total_frame_size
;
602 int sp_adjust
, save_offset
;
605 if (!sibcall_p
&& nios2_can_use_return_insn ())
607 emit_jump_insn (gen_return ());
611 emit_insn (gen_blockage ());
613 total_frame_size
= nios2_compute_frame_layout ();
614 if (frame_pointer_needed
)
616 /* Recover the stack pointer. */
617 insn
= emit_insn (gen_add3_insn
618 (stack_pointer_rtx
, hard_frame_pointer_rtx
,
619 gen_int_mode (-cfun
->machine
->fp_save_offset
, Pmode
)));
620 cfa_adj
= plus_constant (Pmode
, stack_pointer_rtx
,
622 - cfun
->machine
->save_regs_offset
));
623 add_reg_note (insn
, REG_CFA_DEF_CFA
, cfa_adj
);
624 RTX_FRAME_RELATED_P (insn
) = 1;
627 sp_adjust
= total_frame_size
- cfun
->machine
->save_regs_offset
;
629 else if (!SMALL_INT (total_frame_size
))
631 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
632 emit_move_insn (tmp
, gen_int_mode (cfun
->machine
->save_regs_offset
,
634 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
, tmp
));
635 cfa_adj
= gen_rtx_SET (stack_pointer_rtx
,
636 plus_constant (Pmode
, stack_pointer_rtx
,
637 cfun
->machine
->save_regs_offset
));
638 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, cfa_adj
);
639 RTX_FRAME_RELATED_P (insn
) = 1;
641 sp_adjust
= total_frame_size
- cfun
->machine
->save_regs_offset
;
645 save_offset
= cfun
->machine
->save_regs_offset
;
646 sp_adjust
= total_frame_size
;
649 save_offset
+= cfun
->machine
->save_reg_size
;
651 for (regno
= LAST_GP_REG
; regno
> 0; regno
--)
652 if (cfun
->machine
->save_mask
& (1 << regno
))
655 restore_reg (regno
, save_offset
);
660 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
,
661 gen_int_mode (sp_adjust
, Pmode
)));
662 cfa_adj
= gen_rtx_SET (stack_pointer_rtx
,
663 plus_constant (Pmode
, stack_pointer_rtx
,
665 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, cfa_adj
);
666 RTX_FRAME_RELATED_P (insn
) = 1;
669 /* Add in the __builtin_eh_return stack adjustment. */
670 if (crtl
->calls_eh_return
)
671 emit_insn (gen_add2_insn (stack_pointer_rtx
, EH_RETURN_STACKADJ_RTX
));
674 emit_jump_insn (gen_simple_return ());
677 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
678 back to a previous frame. */
680 nios2_get_return_address (int count
)
685 return get_hard_reg_initial_val (Pmode
, RA_REGNO
);
688 /* Emit code to change the current function's return address to
689 ADDRESS. SCRATCH is available as a scratch register, if needed.
690 ADDRESS and SCRATCH are both word-mode GPRs. */
692 nios2_set_return_address (rtx address
, rtx scratch
)
694 nios2_compute_frame_layout ();
695 if (cfun
->machine
->save_mask
& (1 << RA_REGNO
))
697 unsigned offset
= cfun
->machine
->save_reg_size
- 4;
700 if (frame_pointer_needed
)
701 base
= hard_frame_pointer_rtx
;
704 base
= stack_pointer_rtx
;
705 offset
+= cfun
->machine
->save_regs_offset
;
707 if (!SMALL_INT (offset
))
709 emit_move_insn (scratch
, gen_int_mode (offset
, Pmode
));
710 emit_insn (gen_add2_insn (scratch
, base
));
716 base
= plus_constant (Pmode
, base
, offset
);
717 emit_move_insn (gen_rtx_MEM (Pmode
, base
), address
);
720 emit_move_insn (gen_rtx_REG (Pmode
, RA_REGNO
), address
);
723 /* Implement FUNCTION_PROFILER macro. */
725 nios2_function_profiler (FILE *file
, int labelno ATTRIBUTE_UNUSED
)
727 fprintf (file
, "\tmov\tr8, ra\n");
730 fprintf (file
, "\tnextpc\tr2\n");
731 fprintf (file
, "\t1: movhi\tr3, %%hiadj(_gp_got - 1b)\n");
732 fprintf (file
, "\taddi\tr3, r3, %%lo(_gp_got - 1b)\n");
733 fprintf (file
, "\tadd\tr2, r2, r3\n");
734 fprintf (file
, "\tldw\tr2, %%call(_mcount)(r2)\n");
735 fprintf (file
, "\tcallr\tr2\n");
737 else if (flag_pic
== 2)
739 fprintf (file
, "\tnextpc\tr2\n");
740 fprintf (file
, "\t1: movhi\tr3, %%hiadj(_gp_got - 1b)\n");
741 fprintf (file
, "\taddi\tr3, r3, %%lo(_gp_got - 1b)\n");
742 fprintf (file
, "\tadd\tr2, r2, r3\n");
743 fprintf (file
, "\tmovhi\tr3, %%call_hiadj(_mcount)\n");
744 fprintf (file
, "\taddi\tr3, r3, %%call_lo(_mcount)\n");
745 fprintf (file
, "\tadd\tr3, r2, r3\n");
746 fprintf (file
, "\tldw\tr2, 0(r3)\n");
747 fprintf (file
, "\tcallr\tr2\n");
750 fprintf (file
, "\tcall\t_mcount\n");
751 fprintf (file
, "\tmov\tra, r8\n");
754 /* Dump stack layout. */
756 nios2_dump_frame_layout (FILE *file
)
758 fprintf (file
, "\t%s Current Frame Info\n", ASM_COMMENT_START
);
759 fprintf (file
, "\t%s total_size = %d\n", ASM_COMMENT_START
,
760 cfun
->machine
->total_size
);
761 fprintf (file
, "\t%s var_size = %d\n", ASM_COMMENT_START
,
762 cfun
->machine
->var_size
);
763 fprintf (file
, "\t%s args_size = %d\n", ASM_COMMENT_START
,
764 cfun
->machine
->args_size
);
765 fprintf (file
, "\t%s save_reg_size = %d\n", ASM_COMMENT_START
,
766 cfun
->machine
->save_reg_size
);
767 fprintf (file
, "\t%s initialized = %d\n", ASM_COMMENT_START
,
768 cfun
->machine
->initialized
);
769 fprintf (file
, "\t%s save_regs_offset = %d\n", ASM_COMMENT_START
,
770 cfun
->machine
->save_regs_offset
);
771 fprintf (file
, "\t%s is_leaf = %d\n", ASM_COMMENT_START
,
773 fprintf (file
, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START
,
774 frame_pointer_needed
);
775 fprintf (file
, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START
,
776 crtl
->args
.pretend_args_size
);
779 /* Return true if REGNO should be saved in the prologue. */
781 prologue_saved_reg_p (unsigned regno
)
783 gcc_assert (GP_REG_P (regno
));
785 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
788 if (regno
== HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed
)
791 if (regno
== PIC_OFFSET_TABLE_REGNUM
&& crtl
->uses_pic_offset_table
)
794 if (regno
== RA_REGNO
&& df_regs_ever_live_p (RA_REGNO
))
800 /* Implement TARGET_CAN_ELIMINATE. */
802 nios2_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
804 if (to
== STACK_POINTER_REGNUM
)
805 return !frame_pointer_needed
;
809 /* Implement INITIAL_ELIMINATION_OFFSET macro. */
811 nios2_initial_elimination_offset (int from
, int to
)
815 nios2_compute_frame_layout ();
817 /* Set OFFSET to the offset from the stack pointer. */
820 case FRAME_POINTER_REGNUM
:
821 offset
= cfun
->machine
->args_size
;
824 case ARG_POINTER_REGNUM
:
825 offset
= cfun
->machine
->total_size
;
826 offset
-= crtl
->args
.pretend_args_size
;
833 /* If we are asked for the frame pointer offset, then adjust OFFSET
834 by the offset from the frame pointer to the stack pointer. */
835 if (to
== HARD_FRAME_POINTER_REGNUM
)
836 offset
-= (cfun
->machine
->save_regs_offset
837 + cfun
->machine
->fp_save_offset
);
842 /* Return nonzero if this function is known to have a null epilogue.
843 This allows the optimizer to omit jumps to jumps if no stack
846 nios2_can_use_return_insn (void)
848 if (!reload_completed
|| crtl
->profile
)
851 return nios2_compute_frame_layout () == 0;
855 /* Check and signal some warnings/errors on FPU insn options. */
857 nios2_custom_check_insns (void)
862 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
863 if (N2FPU_ENABLED_P (i
) && N2FPU_DOUBLE_P (i
))
865 for (j
= 0; j
< ARRAY_SIZE (nios2_fpu_insn
); j
++)
866 if (N2FPU_DOUBLE_REQUIRED_P (j
) && ! N2FPU_ENABLED_P (j
))
868 error ("switch %<-mcustom-%s%> is required for double "
869 "precision floating point", N2FPU_NAME (j
));
875 /* Warn if the user has certain exotic operations that won't get used
876 without -funsafe-math-optimizations. See expand_builtin () in
878 if (!flag_unsafe_math_optimizations
)
879 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
880 if (N2FPU_ENABLED_P (i
) && N2FPU_UNSAFE_P (i
))
881 warning (0, "switch %<-mcustom-%s%> has no effect unless "
882 "-funsafe-math-optimizations is specified", N2FPU_NAME (i
));
884 /* Warn if the user is trying to use -mcustom-fmins et. al, that won't
885 get used without -ffinite-math-only. See fold_builtin_fmin_fmax ()
887 if (!flag_finite_math_only
)
888 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
889 if (N2FPU_ENABLED_P (i
) && N2FPU_FINITE_P (i
))
890 warning (0, "switch %<-mcustom-%s%> has no effect unless "
891 "-ffinite-math-only is specified", N2FPU_NAME (i
));
893 /* Warn if the user is trying to use a custom rounding instruction
894 that won't get used without -fno-math-errno. See
895 expand_builtin_int_roundingfn_2 () in builtins.c. */
897 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
898 if (N2FPU_ENABLED_P (i
) && N2FPU_NO_ERRNO_P (i
))
899 warning (0, "switch %<-mcustom-%s%> has no effect unless "
900 "-fno-math-errno is specified", N2FPU_NAME (i
));
902 if (errors
|| custom_code_conflict
)
903 fatal_error (input_location
,
904 "conflicting use of -mcustom switches, target attributes, "
905 "and/or __builtin_custom_ functions");
909 nios2_set_fpu_custom_code (enum n2fpu_code code
, int n
, bool override_p
)
911 if (override_p
|| N2FPU_N (code
) == -1)
913 nios2_register_custom_code (n
, CCS_FPU
, (int) code
);
916 /* Type to represent a standard FPU config. */
917 struct nios2_fpu_config
920 bool set_sp_constants
;
921 int code
[n2fpu_code_num
];
924 #define NIOS2_FPU_CONFIG_NUM 3
925 static struct nios2_fpu_config custom_fpu_config
[NIOS2_FPU_CONFIG_NUM
];
928 nios2_init_fpu_configs (void)
930 struct nios2_fpu_config
* cfg
;
932 #define NEXT_FPU_CONFIG \
934 cfg = &custom_fpu_config[i++]; \
935 memset (cfg, -1, sizeof (struct nios2_fpu_config));\
940 cfg
->set_sp_constants
= true;
941 cfg
->code
[n2fpu_fmuls
] = 252;
942 cfg
->code
[n2fpu_fadds
] = 253;
943 cfg
->code
[n2fpu_fsubs
] = 254;
947 cfg
->set_sp_constants
= true;
948 cfg
->code
[n2fpu_fmuls
] = 252;
949 cfg
->code
[n2fpu_fadds
] = 253;
950 cfg
->code
[n2fpu_fsubs
] = 254;
951 cfg
->code
[n2fpu_fdivs
] = 255;
955 cfg
->set_sp_constants
= true;
956 cfg
->code
[n2fpu_floatus
] = 243;
957 cfg
->code
[n2fpu_fixsi
] = 244;
958 cfg
->code
[n2fpu_floatis
] = 245;
959 cfg
->code
[n2fpu_fcmpgts
] = 246;
960 cfg
->code
[n2fpu_fcmples
] = 249;
961 cfg
->code
[n2fpu_fcmpeqs
] = 250;
962 cfg
->code
[n2fpu_fcmpnes
] = 251;
963 cfg
->code
[n2fpu_fmuls
] = 252;
964 cfg
->code
[n2fpu_fadds
] = 253;
965 cfg
->code
[n2fpu_fsubs
] = 254;
966 cfg
->code
[n2fpu_fdivs
] = 255;
968 #undef NEXT_FPU_CONFIG
969 gcc_assert (i
== NIOS2_FPU_CONFIG_NUM
);
972 static struct nios2_fpu_config
*
973 nios2_match_custom_fpu_cfg (const char *cfgname
, const char *endp
)
976 for (i
= 0; i
< NIOS2_FPU_CONFIG_NUM
; i
++)
978 bool match
= !(endp
!= NULL
979 ? strncmp (custom_fpu_config
[i
].name
, cfgname
,
981 : strcmp (custom_fpu_config
[i
].name
, cfgname
));
983 return &custom_fpu_config
[i
];
988 /* Use CFGNAME to lookup FPU config, ENDP if not NULL marks end of string.
989 OVERRIDE is true if loaded config codes should overwrite current state. */
991 nios2_handle_custom_fpu_cfg (const char *cfgname
, const char *endp
,
994 struct nios2_fpu_config
*cfg
= nios2_match_custom_fpu_cfg (cfgname
, endp
);
998 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
999 if (cfg
->code
[i
] >= 0)
1000 nios2_set_fpu_custom_code ((enum n2fpu_code
) i
, cfg
->code
[i
],
1002 if (cfg
->set_sp_constants
)
1003 flag_single_precision_constant
= 1;
1006 warning (0, "ignoring unrecognized switch %<-mcustom-fpu-cfg%> "
1007 "value %<%s%>", cfgname
);
1009 /* Guard against errors in the standard configurations. */
1010 nios2_custom_check_insns ();
1013 /* Check individual FPU insn options, and register custom code. */
1015 nios2_handle_custom_fpu_insn_option (int fpu_insn_index
)
1017 int param
= N2FPU_N (fpu_insn_index
);
1019 if (0 <= param
&& param
<= 255)
1020 nios2_register_custom_code (param
, CCS_FPU
, fpu_insn_index
);
1022 /* Valid values are 0-255, but also allow -1 so that the
1023 -mno-custom-<opt> switches work. */
1024 else if (param
!= -1)
1025 error ("switch %<-mcustom-%s%> value %d must be between 0 and 255",
1026 N2FPU_NAME (fpu_insn_index
), param
);
1029 /* Allocate a chunk of memory for per-function machine-dependent data. */
1030 static struct machine_function
*
1031 nios2_init_machine_status (void)
1033 return ggc_cleared_alloc
<machine_function
> ();
1036 /* Implement TARGET_OPTION_OVERRIDE. */
1038 nios2_option_override (void)
1042 #ifdef SUBTARGET_OVERRIDE_OPTIONS
1043 SUBTARGET_OVERRIDE_OPTIONS
;
1046 /* Check for unsupported options. */
1047 if (flag_pic
&& !TARGET_LINUX_ABI
)
1048 sorry ("position-independent code requires the Linux ABI");
1050 /* Function to allocate machine-dependent function status. */
1051 init_machine_status
= &nios2_init_machine_status
;
1053 nios2_section_threshold
1054 = (global_options_set
.x_g_switch_value
1055 ? g_switch_value
: NIOS2_DEFAULT_GVALUE
);
1057 if (nios2_gpopt_option
== gpopt_unspecified
)
1059 /* Default to -mgpopt unless -fpic or -fPIC. */
1061 nios2_gpopt_option
= gpopt_none
;
1063 nios2_gpopt_option
= gpopt_local
;
1066 /* If we don't have mul, we don't have mulx either! */
1067 if (!TARGET_HAS_MUL
&& TARGET_HAS_MULX
)
1068 target_flags
&= ~MASK_HAS_MULX
;
1070 /* Initialize default FPU configurations. */
1071 nios2_init_fpu_configs ();
1073 /* Set up default handling for floating point custom instructions.
1075 Putting things in this order means that the -mcustom-fpu-cfg=
1076 switch will always be overridden by individual -mcustom-fadds=
1077 switches, regardless of the order in which they were specified
1078 on the command line.
1080 This behavior of prioritization of individual -mcustom-<insn>=
1081 options before the -mcustom-fpu-cfg= switch is maintained for
1083 if (nios2_custom_fpu_cfg_string
&& *nios2_custom_fpu_cfg_string
)
1084 nios2_handle_custom_fpu_cfg (nios2_custom_fpu_cfg_string
, NULL
, false);
1086 /* Handle options for individual FPU insns. */
1087 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
1088 nios2_handle_custom_fpu_insn_option (i
);
1090 nios2_custom_check_insns ();
1092 /* Save the initial options in case the user does function specific
1094 target_option_default_node
= target_option_current_node
1095 = build_target_option_node (&global_options
);
1099 /* Return true if CST is a constant within range of movi/movui/movhi. */
1101 nios2_simple_const_p (const_rtx cst
)
1103 HOST_WIDE_INT val
= INTVAL (cst
);
1104 return SMALL_INT (val
) || SMALL_INT_UNSIGNED (val
) || UPPER16_INT (val
);
1107 /* Compute a (partial) cost for rtx X. Return true if the complete
1108 cost has been computed, and false if subexpressions should be
1109 scanned. In either case, *TOTAL contains the cost result. */
1111 nios2_rtx_costs (rtx x
, int code
, int outer_code ATTRIBUTE_UNUSED
,
1112 int opno ATTRIBUTE_UNUSED
,
1113 int *total
, bool speed ATTRIBUTE_UNUSED
)
1118 if (INTVAL (x
) == 0)
1120 *total
= COSTS_N_INSNS (0);
1123 else if (nios2_simple_const_p (x
))
1125 *total
= COSTS_N_INSNS (2);
1130 *total
= COSTS_N_INSNS (4);
1139 *total
= COSTS_N_INSNS (4);
1145 /* Recognize 'nor' insn pattern. */
1146 if (GET_CODE (XEXP (x
, 0)) == NOT
1147 && GET_CODE (XEXP (x
, 1)) == NOT
)
1149 *total
= COSTS_N_INSNS (1);
1157 *total
= COSTS_N_INSNS (1);
1162 *total
= COSTS_N_INSNS (3);
1167 *total
= COSTS_N_INSNS (1);
1176 /* Implement TARGET_PREFERRED_RELOAD_CLASS. */
1178 nios2_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, reg_class_t regclass
)
1180 return regclass
== NO_REGS
? GENERAL_REGS
: regclass
;
1183 /* Emit a call to __tls_get_addr. TI is the argument to this function.
1184 RET is an RTX for the return value location. The entire insn sequence
1186 static GTY(()) rtx nios2_tls_symbol
;
1189 nios2_call_tls_get_addr (rtx ti
)
1191 rtx arg
= gen_rtx_REG (Pmode
, FIRST_ARG_REGNO
);
1192 rtx ret
= gen_rtx_REG (Pmode
, FIRST_RETVAL_REGNO
);
1195 if (!nios2_tls_symbol
)
1196 nios2_tls_symbol
= init_one_libfunc ("__tls_get_addr");
1198 emit_move_insn (arg
, ti
);
1199 fn
= gen_rtx_MEM (QImode
, nios2_tls_symbol
);
1200 insn
= emit_call_insn (gen_call_value (ret
, fn
, const0_rtx
));
1201 RTL_CONST_CALL_P (insn
) = 1;
1202 use_reg (&CALL_INSN_FUNCTION_USAGE (insn
), ret
);
1203 use_reg (&CALL_INSN_FUNCTION_USAGE (insn
), arg
);
1208 /* Return true for large offsets requiring hiadj/lo relocation pairs. */
1210 nios2_large_offset_p (int unspec
)
1212 gcc_assert (nios2_unspec_reloc_name (unspec
) != NULL
);
1215 /* FIXME: TLS GOT offset relocations will eventually also get this
1216 treatment, after binutils support for those are also completed. */
1217 && (unspec
== UNSPEC_PIC_SYM
|| unspec
== UNSPEC_PIC_CALL_SYM
))
1220 /* 'gotoff' offsets are always hiadj/lo. */
1221 if (unspec
== UNSPEC_PIC_GOTOFF_SYM
)
1227 /* Return true for conforming unspec relocations. Also used in
1228 constraints.md and predicates.md. */
1230 nios2_unspec_reloc_p (rtx op
)
1232 return (GET_CODE (op
) == CONST
1233 && GET_CODE (XEXP (op
, 0)) == UNSPEC
1234 && ! nios2_large_offset_p (XINT (XEXP (op
, 0), 1)));
1237 /* Helper to generate unspec constant. */
1239 nios2_unspec_offset (rtx loc
, int unspec
)
1241 return gen_rtx_CONST (Pmode
, gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, loc
),
1245 /* Generate GOT pointer based address with large offset. */
1247 nios2_large_got_address (rtx offset
, rtx tmp
)
1250 tmp
= gen_reg_rtx (Pmode
);
1251 emit_move_insn (tmp
, offset
);
1252 return gen_rtx_PLUS (Pmode
, tmp
, pic_offset_table_rtx
);
1255 /* Generate a GOT pointer based address. */
1257 nios2_got_address (rtx loc
, int unspec
)
1259 rtx offset
= nios2_unspec_offset (loc
, unspec
);
1260 crtl
->uses_pic_offset_table
= 1;
1262 if (nios2_large_offset_p (unspec
))
1263 return force_reg (Pmode
, nios2_large_got_address (offset
, NULL_RTX
));
1265 return gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, offset
);
1268 /* Generate the code to access LOC, a thread local SYMBOL_REF. The
1269 return value will be a valid address and move_operand (either a REG
1272 nios2_legitimize_tls_address (rtx loc
)
1275 enum tls_model model
= SYMBOL_REF_TLS_MODEL (loc
);
1279 case TLS_MODEL_GLOBAL_DYNAMIC
:
1280 tmp
= gen_reg_rtx (Pmode
);
1281 emit_move_insn (tmp
, nios2_got_address (loc
, UNSPEC_ADD_TLS_GD
));
1282 return nios2_call_tls_get_addr (tmp
);
1284 case TLS_MODEL_LOCAL_DYNAMIC
:
1285 tmp
= gen_reg_rtx (Pmode
);
1286 emit_move_insn (tmp
, nios2_got_address (loc
, UNSPEC_ADD_TLS_LDM
));
1287 return gen_rtx_PLUS (Pmode
, nios2_call_tls_get_addr (tmp
),
1288 nios2_unspec_offset (loc
, UNSPEC_ADD_TLS_LDO
));
1290 case TLS_MODEL_INITIAL_EXEC
:
1291 tmp
= gen_reg_rtx (Pmode
);
1292 mem
= gen_const_mem (Pmode
, nios2_got_address (loc
, UNSPEC_LOAD_TLS_IE
));
1293 emit_move_insn (tmp
, mem
);
1294 tp
= gen_rtx_REG (Pmode
, TP_REGNO
);
1295 return gen_rtx_PLUS (Pmode
, tp
, tmp
);
1297 case TLS_MODEL_LOCAL_EXEC
:
1298 tp
= gen_rtx_REG (Pmode
, TP_REGNO
);
1299 return gen_rtx_PLUS (Pmode
, tp
,
1300 nios2_unspec_offset (loc
, UNSPEC_ADD_TLS_LE
));
1308 If -O3 is used, we want to output a table lookup for
1309 divides between small numbers (both num and den >= 0
1310 and < 0x10). The overhead of this method in the worst
1311 case is 40 bytes in the text section (10 insns) and
1312 256 bytes in the data section. Additional divides do
1313 not incur additional penalties in the data section.
1315 Code speed is improved for small divides by about 5x
1316 when using this method in the worse case (~9 cycles
1317 vs ~45). And in the worst case divides not within the
1318 table are penalized by about 10% (~5 cycles vs ~45).
1319 However in the typical case the penalty is not as bad
1320 because doing the long divide in only 45 cycles is
1323 ??? would be nice to have some benchmarks other
1324 than Dhrystone to back this up.
1326 This bit of expansion is to create this instruction
1333 add $12, $11, divide_table
1339 # continue here with result in $2
1341 ??? Ideally I would like the libcall block to contain all
1342 of this code, but I don't know how to do that. What it
1343 means is that if the divide can be eliminated, it may not
1344 completely disappear.
1346 ??? The __divsi3_table label should ideally be moved out
1347 of this block and into a global. If it is placed into the
1348 sdata section we can save even more cycles by doing things
1351 nios2_emit_expensive_div (rtx
*operands
, machine_mode mode
)
1353 rtx or_result
, shift_left_result
;
1355 rtx_code_label
*lab1
, *lab3
;
1362 /* It may look a little generic, but only SImode is supported for now. */
1363 gcc_assert (mode
== SImode
);
1364 libfunc
= optab_libfunc (sdiv_optab
, SImode
);
1366 lab1
= gen_label_rtx ();
1367 lab3
= gen_label_rtx ();
1369 or_result
= expand_simple_binop (SImode
, IOR
,
1370 operands
[1], operands
[2],
1371 0, 0, OPTAB_LIB_WIDEN
);
1373 emit_cmp_and_jump_insns (or_result
, GEN_INT (15), GTU
, 0,
1374 GET_MODE (or_result
), 0, lab3
);
1375 JUMP_LABEL (get_last_insn ()) = lab3
;
1377 shift_left_result
= expand_simple_binop (SImode
, ASHIFT
,
1378 operands
[1], GEN_INT (4),
1379 0, 0, OPTAB_LIB_WIDEN
);
1381 lookup_value
= expand_simple_binop (SImode
, IOR
,
1382 shift_left_result
, operands
[2],
1383 0, 0, OPTAB_LIB_WIDEN
);
1384 table
= gen_rtx_PLUS (SImode
, lookup_value
,
1385 gen_rtx_SYMBOL_REF (SImode
, "__divsi3_table"));
1386 convert_move (operands
[0], gen_rtx_MEM (QImode
, table
), 1);
1388 tmp
= emit_jump_insn (gen_jump (lab1
));
1389 JUMP_LABEL (tmp
) = lab1
;
1393 LABEL_NUSES (lab3
) = 1;
1396 final_result
= emit_library_call_value (libfunc
, NULL_RTX
,
1397 LCT_CONST
, SImode
, 2,
1398 operands
[1], SImode
,
1399 operands
[2], SImode
);
1401 insns
= get_insns ();
1403 emit_libcall_block (insns
, operands
[0], final_result
,
1404 gen_rtx_DIV (SImode
, operands
[1], operands
[2]));
1407 LABEL_NUSES (lab1
) = 1;
1411 /* Branches and compares. */
1413 /* Return in *ALT_CODE and *ALT_OP, an alternate equivalent constant
1414 comparison, e.g. >= 1 into > 0. */
1416 nios2_alternate_compare_const (enum rtx_code code
, rtx op
,
1417 enum rtx_code
*alt_code
, rtx
*alt_op
,
1420 HOST_WIDE_INT opval
= INTVAL (op
);
1421 enum rtx_code scode
= signed_condition (code
);
1422 bool dec_p
= (scode
== LT
|| scode
== GE
);
1424 if (code
== EQ
|| code
== NE
)
1432 ? gen_int_mode (opval
- 1, mode
)
1433 : gen_int_mode (opval
+ 1, mode
));
1435 /* The required conversion between [>,>=] and [<,<=] is captured
1436 by a reverse + swap of condition codes. */
1437 *alt_code
= reverse_condition (swap_condition (code
));
1440 /* Test if the incremented/decremented value crosses the over/underflow
1441 boundary. Supposedly, such boundary cases should already be transformed
1442 into always-true/false or EQ conditions, so use an assertion here. */
1443 unsigned HOST_WIDE_INT alt_opval
= INTVAL (*alt_op
);
1445 alt_opval
^= (1 << (GET_MODE_BITSIZE (mode
) - 1));
1446 alt_opval
&= GET_MODE_MASK (mode
);
1447 gcc_assert (dec_p
? alt_opval
!= GET_MODE_MASK (mode
) : alt_opval
!= 0);
1451 /* Return true if the constant comparison is supported by nios2. */
1453 nios2_valid_compare_const_p (enum rtx_code code
, rtx op
)
1457 case EQ
: case NE
: case GE
: case LT
:
1458 return SMALL_INT (INTVAL (op
));
1460 return SMALL_INT_UNSIGNED (INTVAL (op
));
1466 /* Checks if the FPU comparison in *CMP, *OP1, and *OP2 can be supported in
1467 the current configuration. Perform modifications if MODIFY_P is true.
1468 Returns true if FPU compare can be done. */
1471 nios2_validate_fpu_compare (machine_mode mode
, rtx
*cmp
, rtx
*op1
, rtx
*op2
,
1475 enum rtx_code code
= GET_CODE (*cmp
);
1477 if (!nios2_fpu_compare_enabled (code
, mode
))
1479 code
= swap_condition (code
);
1480 if (nios2_fpu_compare_enabled (code
, mode
))
1494 *op1
= force_reg (mode
, *op1
);
1495 *op2
= force_reg (mode
, *op2
);
1496 *cmp
= gen_rtx_fmt_ee (code
, mode
, *op1
, *op2
);
1501 /* Checks and modifies the comparison in *CMP, *OP1, and *OP2 into valid
1502 nios2 supported form. Returns true if success. */
1504 nios2_validate_compare (machine_mode mode
, rtx
*cmp
, rtx
*op1
, rtx
*op2
)
1506 enum rtx_code code
= GET_CODE (*cmp
);
1507 enum rtx_code alt_code
;
1510 if (GET_MODE_CLASS (mode
) == MODE_FLOAT
)
1511 return nios2_validate_fpu_compare (mode
, cmp
, op1
, op2
, true);
1513 if (!reg_or_0_operand (*op2
, mode
))
1515 /* Create alternate constant compare. */
1516 nios2_alternate_compare_const (code
, *op2
, &alt_code
, &alt_op2
, mode
);
1518 /* If alterate op2 is zero(0), we can use it directly, possibly
1519 swapping the compare code. */
1520 if (alt_op2
== const0_rtx
)
1524 goto check_rebuild_cmp
;
1527 /* Check if either constant compare can be used. */
1528 if (nios2_valid_compare_const_p (code
, *op2
))
1530 else if (nios2_valid_compare_const_p (alt_code
, alt_op2
))
1537 /* We have to force op2 into a register now. Try to pick one
1538 with a lower cost. */
1539 if (! nios2_simple_const_p (*op2
)
1540 && nios2_simple_const_p (alt_op2
))
1545 *op2
= force_reg (SImode
, *op2
);
1548 if (code
== GT
|| code
== GTU
|| code
== LE
|| code
== LEU
)
1550 rtx t
= *op1
; *op1
= *op2
; *op2
= t
;
1551 code
= swap_condition (code
);
1554 *cmp
= gen_rtx_fmt_ee (code
, mode
, *op1
, *op2
);
1559 /* Addressing Modes. */
1561 /* Implement TARGET_LEGITIMATE_CONSTANT_P. */
1563 nios2_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
1566 split_const (x
, &base
, &offset
);
1567 return GET_CODE (base
) != SYMBOL_REF
|| !SYMBOL_REF_TLS_MODEL (base
);
1570 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
1572 nios2_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
1574 return nios2_legitimate_constant_p (mode
, x
) == false;
1577 /* Return true if register REGNO is a valid base register.
1578 STRICT_P is true if REG_OK_STRICT is in effect. */
1581 nios2_regno_ok_for_base_p (int regno
, bool strict_p
)
1583 if (!HARD_REGISTER_NUM_P (regno
))
1591 regno
= reg_renumber
[regno
];
1594 /* The fake registers will be eliminated to either the stack or
1595 hard frame pointer, both of which are usually valid base registers.
1596 Reload deals with the cases where the eliminated form isn't valid. */
1597 return (GP_REG_P (regno
)
1598 || regno
== FRAME_POINTER_REGNUM
1599 || regno
== ARG_POINTER_REGNUM
);
1602 /* Return true if the address expression formed by BASE + OFFSET is
1605 nios2_valid_addr_expr_p (rtx base
, rtx offset
, bool strict_p
)
1607 if (!strict_p
&& GET_CODE (base
) == SUBREG
)
1608 base
= SUBREG_REG (base
);
1609 return (REG_P (base
)
1610 && nios2_regno_ok_for_base_p (REGNO (base
), strict_p
)
1611 && (offset
== NULL_RTX
1612 || const_arith_operand (offset
, Pmode
)
1613 || nios2_unspec_reloc_p (offset
)));
1616 /* Implement TARGET_LEGITIMATE_ADDRESS_P. */
1618 nios2_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED
,
1619 rtx operand
, bool strict_p
)
1621 switch (GET_CODE (operand
))
1625 if (SYMBOL_REF_TLS_MODEL (operand
))
1628 if (nios2_symbol_ref_in_small_data_p (operand
))
1631 /* Else, fall through. */
1638 /* Register indirect. */
1640 return nios2_regno_ok_for_base_p (REGNO (operand
), strict_p
);
1642 /* Register indirect with displacement. */
1645 rtx op0
= XEXP (operand
, 0);
1646 rtx op1
= XEXP (operand
, 1);
1648 return (nios2_valid_addr_expr_p (op0
, op1
, strict_p
)
1649 || nios2_valid_addr_expr_p (op1
, op0
, strict_p
));
1658 /* Return true if SECTION is a small section name. */
1660 nios2_small_section_name_p (const char *section
)
1662 return (strcmp (section
, ".sbss") == 0
1663 || strncmp (section
, ".sbss.", 6) == 0
1664 || strcmp (section
, ".sdata") == 0
1665 || strncmp (section
, ".sdata.", 7) == 0);
1668 /* Return true if EXP should be placed in the small data section. */
1670 nios2_in_small_data_p (const_tree exp
)
1672 /* We want to merge strings, so we never consider them small data. */
1673 if (TREE_CODE (exp
) == STRING_CST
)
1676 if (TREE_CODE (exp
) == VAR_DECL
)
1678 if (DECL_SECTION_NAME (exp
))
1680 const char *section
= DECL_SECTION_NAME (exp
);
1681 if (nios2_small_section_name_p (section
))
1686 HOST_WIDE_INT size
= int_size_in_bytes (TREE_TYPE (exp
));
1688 /* If this is an incomplete type with size 0, then we can't put it
1689 in sdata because it might be too big when completed. */
1691 && (unsigned HOST_WIDE_INT
) size
<= nios2_section_threshold
)
1699 /* Return true if symbol is in small data section. */
1702 nios2_symbol_ref_in_small_data_p (rtx sym
)
1706 gcc_assert (GET_CODE (sym
) == SYMBOL_REF
);
1707 decl
= SYMBOL_REF_DECL (sym
);
1709 /* TLS variables are not accessed through the GP. */
1710 if (SYMBOL_REF_TLS_MODEL (sym
) != 0)
1713 /* If the user has explicitly placed the symbol in a small data section
1714 via an attribute, generate gp-relative addressing even if the symbol
1715 is external, weak, or larger than we'd automatically put in the
1716 small data section. OTOH, if the symbol is located in some
1717 non-small-data section, we can't use gp-relative accesses on it
1718 unless the user has requested gpopt_data or gpopt_all. */
1720 switch (nios2_gpopt_option
)
1723 /* Don't generate a gp-relative addressing mode if that's been
1728 /* Use GP-relative addressing for small data symbols that are
1729 not external or weak, plus any symbols that have explicitly
1730 been placed in a small data section. */
1731 if (decl
&& DECL_SECTION_NAME (decl
))
1732 return nios2_small_section_name_p (DECL_SECTION_NAME (decl
));
1733 return (SYMBOL_REF_SMALL_P (sym
)
1734 && !SYMBOL_REF_EXTERNAL_P (sym
)
1735 && !(decl
&& DECL_WEAK (decl
)));
1738 /* Use GP-relative addressing for small data symbols, even if
1739 they are external or weak. Note that SYMBOL_REF_SMALL_P
1740 is also true of symbols that have explicitly been placed
1741 in a small data section. */
1742 return SYMBOL_REF_SMALL_P (sym
);
1745 /* Use GP-relative addressing for all data symbols regardless
1746 of the object size, but not for code symbols. This option
1747 is equivalent to the user asserting that the entire data
1748 section is accessible from the GP. */
1749 return !SYMBOL_REF_FUNCTION_P (sym
);
1752 /* Use GP-relative addressing for everything, including code.
1753 Effectively, the user has asserted that the entire program
1754 fits within the 64K range of the GP offset. */
1758 /* We shouldn't get here. */
1763 /* Implement TARGET_SECTION_TYPE_FLAGS. */
1766 nios2_section_type_flags (tree decl
, const char *name
, int reloc
)
1770 flags
= default_section_type_flags (decl
, name
, reloc
);
1772 if (nios2_small_section_name_p (name
))
1773 flags
|= SECTION_SMALL
;
1778 /* Return true if SYMBOL_REF X binds locally. */
1781 nios2_symbol_binds_local_p (const_rtx x
)
1783 return (SYMBOL_REF_DECL (x
)
1784 ? targetm
.binds_local_p (SYMBOL_REF_DECL (x
))
1785 : SYMBOL_REF_LOCAL_P (x
));
1788 /* Position independent code related. */
1790 /* Emit code to load the PIC register. */
1792 nios2_load_pic_register (void)
1794 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
1796 emit_insn (gen_load_got_register (pic_offset_table_rtx
, tmp
));
1797 emit_insn (gen_add3_insn (pic_offset_table_rtx
, pic_offset_table_rtx
, tmp
));
1800 /* Generate a PIC address as a MEM rtx. */
1802 nios2_load_pic_address (rtx sym
, int unspec
, rtx tmp
)
1805 && GET_CODE (sym
) == SYMBOL_REF
1806 && nios2_symbol_binds_local_p (sym
))
1807 /* Under -fPIC, generate a GOTOFF address for local symbols. */
1809 rtx offset
= nios2_unspec_offset (sym
, UNSPEC_PIC_GOTOFF_SYM
);
1810 crtl
->uses_pic_offset_table
= 1;
1811 return nios2_large_got_address (offset
, tmp
);
1814 return gen_const_mem (Pmode
, nios2_got_address (sym
, unspec
));
1817 /* Nonzero if the constant value X is a legitimate general operand
1818 when generating PIC code. It is given that flag_pic is on and
1819 that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
1821 nios2_legitimate_pic_operand_p (rtx x
)
1823 if (GET_CODE (x
) == CONST
1824 && GET_CODE (XEXP (x
, 0)) == UNSPEC
1825 && nios2_large_offset_p (XINT (XEXP (x
, 0), 1)))
1828 return ! (GET_CODE (x
) == SYMBOL_REF
1829 || GET_CODE (x
) == LABEL_REF
|| GET_CODE (x
) == CONST
);
1832 /* Return TRUE if X is a thread-local symbol. */
1834 nios2_tls_symbol_p (rtx x
)
1836 return (targetm
.have_tls
&& GET_CODE (x
) == SYMBOL_REF
1837 && SYMBOL_REF_TLS_MODEL (x
) != 0);
1840 /* Legitimize addresses that are CONSTANT_P expressions. */
1842 nios2_legitimize_constant_address (rtx addr
)
1845 split_const (addr
, &base
, &offset
);
1847 if (nios2_tls_symbol_p (base
))
1848 base
= nios2_legitimize_tls_address (base
);
1850 base
= nios2_load_pic_address (base
, UNSPEC_PIC_SYM
, NULL_RTX
);
1854 if (offset
!= const0_rtx
)
1856 gcc_assert (can_create_pseudo_p ());
1857 return gen_rtx_PLUS (Pmode
, force_reg (Pmode
, base
),
1858 (CONST_INT_P (offset
)
1859 ? (SMALL_INT (INTVAL (offset
))
1860 ? offset
: force_reg (Pmode
, offset
))
1866 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1868 nios2_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
1869 machine_mode mode ATTRIBUTE_UNUSED
)
1872 return nios2_legitimize_constant_address (x
);
1874 /* For the TLS LE (Local Exec) model, the compiler may try to
1875 combine constant offsets with unspec relocs, creating address RTXs
1877 (plus:SI (reg:SI 23 r23)
1880 (unspec:SI [(symbol_ref:SI ("var"))] UNSPEC_ADD_TLS_LE)
1881 (const_int 48 [0x30]))))
1883 This usually happens when 'var' is a thread-local struct variable,
1884 and access of a field in var causes the addend.
1886 We typically want this combining, so transform the above into this
1887 form, which is allowed:
1888 (plus:SI (reg:SI 23 r23)
1892 (plus:SI (symbol_ref:SI ("var"))
1893 (const_int 48 [0x30])))] UNSPEC_ADD_TLS_LE)))
1895 Which will be output as '%tls_le(var+48)(r23)' in assembly. */
1896 if (GET_CODE (x
) == PLUS
1897 && GET_CODE (XEXP (x
, 0)) == REG
1898 && GET_CODE (XEXP (x
, 1)) == CONST
)
1900 rtx unspec
, offset
, reg
= XEXP (x
, 0);
1901 split_const (XEXP (x
, 1), &unspec
, &offset
);
1902 if (GET_CODE (unspec
) == UNSPEC
1903 && !nios2_large_offset_p (XINT (unspec
, 1))
1904 && offset
!= const0_rtx
)
1906 unspec
= copy_rtx (unspec
);
1907 XVECEXP (unspec
, 0, 0)
1908 = plus_constant (Pmode
, XVECEXP (unspec
, 0, 0), INTVAL (offset
));
1909 x
= gen_rtx_PLUS (Pmode
, reg
, gen_rtx_CONST (Pmode
, unspec
));
1917 nios2_delegitimize_address (rtx x
)
1919 x
= delegitimize_mem_from_attrs (x
);
1921 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == UNSPEC
)
1923 switch (XINT (XEXP (x
, 0), 1))
1925 case UNSPEC_PIC_SYM
:
1926 case UNSPEC_PIC_CALL_SYM
:
1927 case UNSPEC_PIC_GOTOFF_SYM
:
1928 case UNSPEC_ADD_TLS_GD
:
1929 case UNSPEC_ADD_TLS_LDM
:
1930 case UNSPEC_LOAD_TLS_IE
:
1931 case UNSPEC_ADD_TLS_LE
:
1932 x
= XVECEXP (XEXP (x
, 0), 0, 0);
1933 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
1940 /* Main expander function for RTL moves. */
1942 nios2_emit_move_sequence (rtx
*operands
, machine_mode mode
)
1944 rtx to
= operands
[0];
1945 rtx from
= operands
[1];
1947 if (!register_operand (to
, mode
) && !reg_or_0_operand (from
, mode
))
1949 gcc_assert (can_create_pseudo_p ());
1950 from
= copy_to_mode_reg (mode
, from
);
1953 if (GET_CODE (from
) == SYMBOL_REF
|| GET_CODE (from
) == LABEL_REF
1954 || (GET_CODE (from
) == CONST
1955 && GET_CODE (XEXP (from
, 0)) != UNSPEC
))
1956 from
= nios2_legitimize_constant_address (from
);
1963 /* The function with address *ADDR is being called. If the address
1964 needs to be loaded from the GOT, emit the instruction to do so and
1965 update *ADDR to point to the rtx for the loaded value.
1966 If REG != NULL_RTX, it is used as the target/scratch register in the
1967 GOT address calculation. */
1969 nios2_adjust_call_address (rtx
*call_op
, rtx reg
)
1971 if (MEM_P (*call_op
))
1972 call_op
= &XEXP (*call_op
, 0);
1974 rtx addr
= *call_op
;
1975 if (flag_pic
&& CONSTANT_P (addr
))
1977 rtx tmp
= reg
? reg
: NULL_RTX
;
1979 reg
= gen_reg_rtx (Pmode
);
1980 addr
= nios2_load_pic_address (addr
, UNSPEC_PIC_CALL_SYM
, tmp
);
1981 emit_insn (gen_rtx_SET (reg
, addr
));
1987 /* Output assembly language related definitions. */
1989 /* Print the operand OP to file stream FILE modified by LETTER.
1990 LETTER can be one of:
1992 i: print "i" if OP is an immediate, except 0
1993 o: print "io" if OP is volatile
1994 z: for const0_rtx print $0 instead of 0
1997 U: for upper half of 32 bit value
1998 D: for the upper 32-bits of a 64-bit double value
1999 R: prints reverse condition.
2002 nios2_print_operand (FILE *file
, rtx op
, int letter
)
2008 if (CONSTANT_P (op
) && op
!= const0_rtx
)
2009 fprintf (file
, "i");
2013 if (GET_CODE (op
) == MEM
2014 && ((MEM_VOLATILE_P (op
) && TARGET_BYPASS_CACHE_VOLATILE
)
2015 || TARGET_BYPASS_CACHE
))
2016 fprintf (file
, "io");
2023 if (comparison_operator (op
, VOIDmode
))
2025 enum rtx_code cond
= GET_CODE (op
);
2028 fprintf (file
, "%s", GET_RTX_NAME (cond
));
2033 fprintf (file
, "%s", GET_RTX_NAME (reverse_condition (cond
)));
2038 switch (GET_CODE (op
))
2041 if (letter
== 0 || letter
== 'z')
2043 fprintf (file
, "%s", reg_names
[REGNO (op
)]);
2046 else if (letter
== 'D')
2048 fprintf (file
, "%s", reg_names
[REGNO (op
)+1]);
2054 if (INTVAL (op
) == 0 && letter
== 'z')
2056 fprintf (file
, "zero");
2062 HOST_WIDE_INT val
= INTVAL (op
);
2063 val
= (val
>> 16) & 0xFFFF;
2064 output_addr_const (file
, gen_int_mode (val
, SImode
));
2067 /* Else, fall through. */
2073 if (letter
== 0 || letter
== 'z')
2075 output_addr_const (file
, op
);
2078 else if (letter
== 'H' || letter
== 'L')
2080 fprintf (file
, "%%");
2081 if (GET_CODE (op
) == CONST
2082 && GET_CODE (XEXP (op
, 0)) == UNSPEC
)
2084 rtx unspec
= XEXP (op
, 0);
2085 int unspec_reloc
= XINT (unspec
, 1);
2086 gcc_assert (nios2_large_offset_p (unspec_reloc
));
2087 fprintf (file
, "%s_", nios2_unspec_reloc_name (unspec_reloc
));
2088 op
= XVECEXP (unspec
, 0, 0);
2090 fprintf (file
, letter
== 'H' ? "hiadj(" : "lo(");
2091 output_addr_const (file
, op
);
2092 fprintf (file
, ")");
2101 output_address (op
);
2109 output_addr_const (file
, op
);
2118 output_operand_lossage ("Unsupported operand for code '%c'", letter
);
2122 /* Return true if this is a GP-relative accessible reference. */
2124 gprel_constant_p (rtx op
)
2126 if (GET_CODE (op
) == SYMBOL_REF
2127 && nios2_symbol_ref_in_small_data_p (op
))
2129 else if (GET_CODE (op
) == CONST
2130 && GET_CODE (XEXP (op
, 0)) == PLUS
)
2131 return gprel_constant_p (XEXP (XEXP (op
, 0), 0));
2136 /* Return the name string for a supported unspec reloc offset. */
2138 nios2_unspec_reloc_name (int unspec
)
2142 case UNSPEC_PIC_SYM
:
2144 case UNSPEC_PIC_CALL_SYM
:
2146 case UNSPEC_PIC_GOTOFF_SYM
:
2148 case UNSPEC_LOAD_TLS_IE
:
2150 case UNSPEC_ADD_TLS_LE
:
2152 case UNSPEC_ADD_TLS_GD
:
2154 case UNSPEC_ADD_TLS_LDM
:
2156 case UNSPEC_ADD_TLS_LDO
:
2163 /* Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA. */
2165 nios2_output_addr_const_extra (FILE *file
, rtx op
)
2168 gcc_assert (GET_CODE (op
) == UNSPEC
);
2170 /* Support for printing out const unspec relocations. */
2171 name
= nios2_unspec_reloc_name (XINT (op
, 1));
2174 fprintf (file
, "%%%s(", name
);
2175 output_addr_const (file
, XVECEXP (op
, 0, 0));
2176 fprintf (file
, ")");
2182 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
2184 nios2_print_operand_address (FILE *file
, rtx op
)
2186 switch (GET_CODE (op
))
2193 if (gprel_constant_p (op
))
2195 fprintf (file
, "%%gprel(");
2196 output_addr_const (file
, op
);
2197 fprintf (file
, ")(%s)", reg_names
[GP_REGNO
]);
2205 rtx op0
= XEXP (op
, 0);
2206 rtx op1
= XEXP (op
, 1);
2208 if (REG_P (op0
) && CONSTANT_P (op1
))
2210 output_addr_const (file
, op1
);
2211 fprintf (file
, "(%s)", reg_names
[REGNO (op0
)]);
2214 else if (REG_P (op1
) && CONSTANT_P (op0
))
2216 output_addr_const (file
, op0
);
2217 fprintf (file
, "(%s)", reg_names
[REGNO (op1
)]);
2224 fprintf (file
, "0(%s)", reg_names
[REGNO (op
)]);
2229 rtx base
= XEXP (op
, 0);
2230 nios2_print_operand_address (file
, base
);
2237 fprintf (stderr
, "Missing way to print address\n");
2242 /* Implement TARGET_ASM_OUTPUT_DWARF_DTPREL. */
2244 nios2_output_dwarf_dtprel (FILE *file
, int size
, rtx x
)
2246 gcc_assert (size
== 4);
2247 fprintf (file
, "\t.4byte\t%%tls_ldo(");
2248 output_addr_const (file
, x
);
2249 fprintf (file
, ")");
2252 /* Implemet TARGET_ASM_FILE_END. */
2255 nios2_asm_file_end (void)
2257 /* The Nios II Linux stack is mapped non-executable by default, so add a
2258 .note.GNU-stack section for switching to executable stacks only when
2259 trampolines are generated. */
2260 if (TARGET_LINUX_ABI
&& trampolines_created
)
2261 file_end_indicate_exec_stack ();
2264 /* Implement TARGET_ASM_FUNCTION_PROLOGUE. */
2266 nios2_asm_function_prologue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2268 if (flag_verbose_asm
|| flag_debug_asm
)
2270 nios2_compute_frame_layout ();
2271 nios2_dump_frame_layout (file
);
2275 /* Emit assembly of custom FPU instructions. */
2277 nios2_fpu_insn_asm (enum n2fpu_code code
)
2279 static char buf
[256];
2280 const char *op1
, *op2
, *op3
;
2281 int ln
= 256, n
= 0;
2283 int N
= N2FPU_N (code
);
2284 int num_operands
= N2FPU (code
).num_operands
;
2285 const char *insn_name
= N2FPU_NAME (code
);
2286 tree ftype
= nios2_ftype (N2FPU_FTCODE (code
));
2287 machine_mode dst_mode
= TYPE_MODE (TREE_TYPE (ftype
));
2288 machine_mode src_mode
= TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (ftype
)));
2290 /* Prepare X register for DF input operands. */
2291 if (GET_MODE_SIZE (src_mode
) == 8 && num_operands
== 3)
2292 n
= snprintf (buf
, ln
, "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t",
2293 N2FPU_N (n2fpu_fwrx
));
2295 if (src_mode
== SFmode
)
2297 if (dst_mode
== VOIDmode
)
2299 /* The fwry case. */
2306 op1
= (dst_mode
== DFmode
? "%D0" : "%0");
2308 op3
= (num_operands
== 2 ? "zero" : "%2");
2311 else if (src_mode
== DFmode
)
2313 if (dst_mode
== VOIDmode
)
2315 /* The fwrx case. */
2323 op1
= (dst_mode
== DFmode
? "%D0" : "%0");
2324 op2
= (num_operands
== 2 ? "%1" : "%2");
2325 op3
= (num_operands
== 2 ? "%D1" : "%D2");
2328 else if (src_mode
== VOIDmode
)
2330 /* frdxlo, frdxhi, frdy cases. */
2331 gcc_assert (dst_mode
== SFmode
);
2335 else if (src_mode
== SImode
)
2337 /* Conversion operators. */
2338 gcc_assert (num_operands
== 2);
2339 op1
= (dst_mode
== DFmode
? "%D0" : "%0");
2346 /* Main instruction string. */
2347 n
+= snprintf (buf
+ n
, ln
- n
, "custom\t%d, %s, %s, %s # %s %%0%s%s",
2348 N
, op1
, op2
, op3
, insn_name
,
2349 (num_operands
>= 2 ? ", %1" : ""),
2350 (num_operands
== 3 ? ", %2" : ""));
2352 /* Extraction of Y register for DF results. */
2353 if (dst_mode
== DFmode
)
2354 snprintf (buf
+ n
, ln
- n
, "\n\tcustom\t%d, %%0, zero, zero # frdy %%0",
2355 N2FPU_N (n2fpu_frdy
));
2361 /* Function argument related. */
2363 /* Define where to put the arguments to a function. Value is zero to
2364 push the argument on the stack, or a hard register in which to
2367 MODE is the argument's machine mode.
2368 TYPE is the data type of the argument (as a tree).
2369 This is null for libcalls where that information may
2371 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2372 the preceding args and about the function being called.
2373 NAMED is nonzero if this argument is a named parameter
2374 (otherwise it is an extra parameter matching an ellipsis). */
2377 nios2_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
2378 const_tree type ATTRIBUTE_UNUSED
,
2379 bool named ATTRIBUTE_UNUSED
)
2381 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2382 rtx return_rtx
= NULL_RTX
;
2384 if (cum
->regs_used
< NUM_ARG_REGS
)
2385 return_rtx
= gen_rtx_REG (mode
, FIRST_ARG_REGNO
+ cum
->regs_used
);
2390 /* Return number of bytes, at the beginning of the argument, that must be
2391 put in registers. 0 is the argument is entirely in registers or entirely
2395 nios2_arg_partial_bytes (cumulative_args_t cum_v
,
2396 machine_mode mode
, tree type ATTRIBUTE_UNUSED
,
2397 bool named ATTRIBUTE_UNUSED
)
2399 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2400 HOST_WIDE_INT param_size
;
2402 if (mode
== BLKmode
)
2404 param_size
= int_size_in_bytes (type
);
2405 gcc_assert (param_size
>= 0);
2408 param_size
= GET_MODE_SIZE (mode
);
2410 /* Convert to words (round up). */
2411 param_size
= (UNITS_PER_WORD
- 1 + param_size
) / UNITS_PER_WORD
;
2413 if (cum
->regs_used
< NUM_ARG_REGS
2414 && cum
->regs_used
+ param_size
> NUM_ARG_REGS
)
2415 return (NUM_ARG_REGS
- cum
->regs_used
) * UNITS_PER_WORD
;
2420 /* Update the data in CUM to advance over an argument of mode MODE
2421 and data type TYPE; TYPE is null for libcalls where that information
2422 may not be available. */
2425 nios2_function_arg_advance (cumulative_args_t cum_v
, machine_mode mode
,
2426 const_tree type ATTRIBUTE_UNUSED
,
2427 bool named ATTRIBUTE_UNUSED
)
2429 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2430 HOST_WIDE_INT param_size
;
2432 if (mode
== BLKmode
)
2434 param_size
= int_size_in_bytes (type
);
2435 gcc_assert (param_size
>= 0);
2438 param_size
= GET_MODE_SIZE (mode
);
2440 /* Convert to words (round up). */
2441 param_size
= (UNITS_PER_WORD
- 1 + param_size
) / UNITS_PER_WORD
;
2443 if (cum
->regs_used
+ param_size
> NUM_ARG_REGS
)
2444 cum
->regs_used
= NUM_ARG_REGS
;
2446 cum
->regs_used
+= param_size
;
2450 nios2_function_arg_padding (machine_mode mode
, const_tree type
)
2452 /* On little-endian targets, the first byte of every stack argument
2453 is passed in the first byte of the stack slot. */
2454 if (!BYTES_BIG_ENDIAN
)
2457 /* Otherwise, integral types are padded downward: the last byte of a
2458 stack argument is passed in the last byte of the stack slot. */
2460 ? INTEGRAL_TYPE_P (type
) || POINTER_TYPE_P (type
)
2461 : GET_MODE_CLASS (mode
) == MODE_INT
)
2464 /* Arguments smaller than a stack slot are padded downward. */
2465 if (mode
!= BLKmode
)
2466 return (GET_MODE_BITSIZE (mode
) >= PARM_BOUNDARY
) ? upward
: downward
;
2468 return ((int_size_in_bytes (type
) >= (PARM_BOUNDARY
/ BITS_PER_UNIT
))
2469 ? upward
: downward
);
2473 nios2_block_reg_padding (machine_mode mode
, tree type
,
2474 int first ATTRIBUTE_UNUSED
)
2476 return nios2_function_arg_padding (mode
, type
);
2479 /* Emit RTL insns to initialize the variable parts of a trampoline.
2480 FNADDR is an RTX for the address of the function's pure code.
2481 CXT is an RTX for the static chain value for the function.
2482 On Nios II, we handle this by a library call. */
2484 nios2_trampoline_init (rtx m_tramp
, tree fndecl
, rtx cxt
)
2486 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
2487 rtx ctx_reg
= force_reg (Pmode
, cxt
);
2488 rtx addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
2490 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__trampoline_setup"),
2491 LCT_NORMAL
, VOIDmode
, 3, addr
, Pmode
, fnaddr
, Pmode
,
2495 /* Implement TARGET_FUNCTION_VALUE. */
2497 nios2_function_value (const_tree ret_type
, const_tree fn ATTRIBUTE_UNUSED
,
2498 bool outgoing ATTRIBUTE_UNUSED
)
2500 return gen_rtx_REG (TYPE_MODE (ret_type
), FIRST_RETVAL_REGNO
);
2503 /* Implement TARGET_LIBCALL_VALUE. */
2505 nios2_libcall_value (machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
2507 return gen_rtx_REG (mode
, FIRST_RETVAL_REGNO
);
2510 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
2512 nios2_function_value_regno_p (const unsigned int regno
)
2514 return regno
== FIRST_RETVAL_REGNO
;
2517 /* Implement TARGET_RETURN_IN_MEMORY. */
2519 nios2_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
2521 return (int_size_in_bytes (type
) > (2 * UNITS_PER_WORD
)
2522 || int_size_in_bytes (type
) == -1);
2525 /* TODO: It may be possible to eliminate the copyback and implement
2528 nios2_setup_incoming_varargs (cumulative_args_t cum_v
,
2529 machine_mode mode
, tree type
,
2530 int *pretend_size
, int second_time
)
2532 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2533 CUMULATIVE_ARGS local_cum
;
2534 cumulative_args_t local_cum_v
= pack_cumulative_args (&local_cum
);
2539 nios2_function_arg_advance (local_cum_v
, mode
, type
, 1);
2541 regs_to_push
= NUM_ARG_REGS
- local_cum
.regs_used
;
2543 if (!second_time
&& regs_to_push
> 0)
2545 rtx ptr
= virtual_incoming_args_rtx
;
2546 rtx mem
= gen_rtx_MEM (BLKmode
, ptr
);
2547 emit_insn (gen_blockage ());
2548 move_block_from_reg (local_cum
.regs_used
+ FIRST_ARG_REGNO
, mem
,
2550 emit_insn (gen_blockage ());
2553 pret_size
= regs_to_push
* UNITS_PER_WORD
;
2555 *pretend_size
= pret_size
;
2560 /* Init FPU builtins. */
2562 nios2_init_fpu_builtins (int start_code
)
2565 char builtin_name
[64] = "__builtin_custom_";
2566 unsigned int i
, n
= strlen ("__builtin_custom_");
2568 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
2570 snprintf (builtin_name
+ n
, sizeof (builtin_name
) - n
,
2571 "%s", N2FPU_NAME (i
));
2573 add_builtin_function (builtin_name
, nios2_ftype (N2FPU_FTCODE (i
)),
2574 start_code
+ i
, BUILT_IN_MD
, NULL
, NULL_TREE
);
2575 nios2_register_builtin_fndecl (start_code
+ i
, fndecl
);
2579 /* Helper function for expanding FPU builtins. */
2581 nios2_expand_fpu_builtin (tree exp
, unsigned int code
, rtx target
)
2583 struct expand_operand ops
[MAX_RECOG_OPERANDS
];
2584 enum insn_code icode
= N2FPU_ICODE (code
);
2585 int nargs
, argno
, opno
= 0;
2586 int num_operands
= N2FPU (code
).num_operands
;
2587 machine_mode dst_mode
= TYPE_MODE (TREE_TYPE (exp
));
2588 bool has_target_p
= (dst_mode
!= VOIDmode
);
2590 if (N2FPU_N (code
) < 0)
2591 fatal_error (input_location
,
2592 "Cannot call %<__builtin_custom_%s%> without specifying switch"
2593 " %<-mcustom-%s%>", N2FPU_NAME (code
), N2FPU_NAME (code
));
2595 create_output_operand (&ops
[opno
++], target
, dst_mode
);
2597 /* Subtract away the count of the VOID return, mainly for fwrx/fwry. */
2599 nargs
= call_expr_nargs (exp
);
2600 for (argno
= 0; argno
< nargs
; argno
++)
2602 tree arg
= CALL_EXPR_ARG (exp
, argno
);
2603 create_input_operand (&ops
[opno
++], expand_normal (arg
),
2604 TYPE_MODE (TREE_TYPE (arg
)));
2606 if (!maybe_expand_insn (icode
, num_operands
, ops
))
2608 error ("invalid argument to built-in function");
2609 return has_target_p
? gen_reg_rtx (ops
[0].mode
) : const0_rtx
;
2611 return has_target_p
? ops
[0].value
: const0_rtx
;
2614 /* Nios II has custom instruction built-in functions of the forms:
2617 __builtin_custom_nXX
2619 __builtin_custom_XnX
2620 __builtin_custom_XnXX
2622 where each X could be either 'i' (int), 'f' (float), or 'p' (void*).
2623 Therefore with 0-1 return values, and 0-2 arguments, we have a
2624 total of (3 + 1) * (1 + 3 + 9) == 52 custom builtin functions.
2626 #define NUM_CUSTOM_BUILTINS ((3 + 1) * (1 + 3 + 9))
2627 static char custom_builtin_name
[NUM_CUSTOM_BUILTINS
][5];
2630 nios2_init_custom_builtins (int start_code
)
2632 tree builtin_ftype
, ret_type
, fndecl
;
2633 char builtin_name
[32] = "__builtin_custom_";
2634 int n
= strlen ("__builtin_custom_");
2635 int builtin_code
= 0;
2636 int lhs
, rhs1
, rhs2
;
2638 struct { tree type
; const char *c
; } op
[4];
2639 /* z */ op
[0].c
= ""; op
[0].type
= NULL_TREE
;
2640 /* f */ op
[1].c
= "f"; op
[1].type
= float_type_node
;
2641 /* i */ op
[2].c
= "i"; op
[2].type
= integer_type_node
;
2642 /* p */ op
[3].c
= "p"; op
[3].type
= ptr_type_node
;
2644 /* We enumerate through the possible operand types to create all the
2645 __builtin_custom_XnXX function tree types. Note that these may slightly
2646 overlap with the function types created for other fixed builtins. */
2648 for (lhs
= 0; lhs
< 4; lhs
++)
2649 for (rhs1
= 0; rhs1
< 4; rhs1
++)
2650 for (rhs2
= 0; rhs2
< 4; rhs2
++)
2652 if (rhs1
== 0 && rhs2
!= 0)
2654 ret_type
= (op
[lhs
].type
? op
[lhs
].type
: void_type_node
);
2656 = build_function_type_list (ret_type
, integer_type_node
,
2657 op
[rhs1
].type
, op
[rhs2
].type
,
2659 snprintf (builtin_name
+ n
, 32 - n
, "%sn%s%s",
2660 op
[lhs
].c
, op
[rhs1
].c
, op
[rhs2
].c
);
2661 /* Save copy of parameter string into custom_builtin_name[]. */
2662 strncpy (custom_builtin_name
[builtin_code
], builtin_name
+ n
, 5);
2664 add_builtin_function (builtin_name
, builtin_ftype
,
2665 start_code
+ builtin_code
,
2666 BUILT_IN_MD
, NULL
, NULL_TREE
);
2667 nios2_register_builtin_fndecl (start_code
+ builtin_code
, fndecl
);
2672 /* Helper function for expanding custom builtins. */
2674 nios2_expand_custom_builtin (tree exp
, unsigned int index
, rtx target
)
2676 bool has_target_p
= (TREE_TYPE (exp
) != void_type_node
);
2677 machine_mode tmode
= VOIDmode
;
2679 rtx value
, insn
, unspec_args
[3];
2685 tmode
= TYPE_MODE (TREE_TYPE (exp
));
2686 if (!target
|| GET_MODE (target
) != tmode
2688 target
= gen_reg_rtx (tmode
);
2691 nargs
= call_expr_nargs (exp
);
2692 for (argno
= 0; argno
< nargs
; argno
++)
2694 arg
= CALL_EXPR_ARG (exp
, argno
);
2695 value
= expand_normal (arg
);
2696 unspec_args
[argno
] = value
;
2699 if (!custom_insn_opcode (value
, VOIDmode
))
2700 error ("custom instruction opcode must be compile time "
2701 "constant in the range 0-255 for __builtin_custom_%s",
2702 custom_builtin_name
[index
]);
2705 /* For other arguments, force into a register. */
2706 unspec_args
[argno
] = force_reg (TYPE_MODE (TREE_TYPE (arg
)),
2707 unspec_args
[argno
]);
2709 /* Fill remaining unspec operands with zero. */
2710 for (; argno
< 3; argno
++)
2711 unspec_args
[argno
] = const0_rtx
;
2713 insn
= (has_target_p
2714 ? gen_rtx_SET (target
,
2715 gen_rtx_UNSPEC_VOLATILE (tmode
,
2716 gen_rtvec_v (3, unspec_args
),
2717 UNSPECV_CUSTOM_XNXX
))
2718 : gen_rtx_UNSPEC_VOLATILE (VOIDmode
, gen_rtvec_v (3, unspec_args
),
2719 UNSPECV_CUSTOM_NXX
));
2721 return has_target_p
? target
: const0_rtx
;
2727 /* Main definition of built-in functions. Nios II has a small number of fixed
2728 builtins, plus a large number of FPU insn builtins, and builtins for
2729 generating custom instructions. */
2731 struct nios2_builtin_desc
2733 enum insn_code icode
;
2734 enum nios2_ftcode ftype
;
2738 #define N2_BUILTINS \
2739 N2_BUILTIN_DEF (sync, N2_FTYPE_VOID_VOID) \
2740 N2_BUILTIN_DEF (ldbio, N2_FTYPE_SI_CVPTR) \
2741 N2_BUILTIN_DEF (ldbuio, N2_FTYPE_UI_CVPTR) \
2742 N2_BUILTIN_DEF (ldhio, N2_FTYPE_SI_CVPTR) \
2743 N2_BUILTIN_DEF (ldhuio, N2_FTYPE_UI_CVPTR) \
2744 N2_BUILTIN_DEF (ldwio, N2_FTYPE_SI_CVPTR) \
2745 N2_BUILTIN_DEF (stbio, N2_FTYPE_VOID_VPTR_SI) \
2746 N2_BUILTIN_DEF (sthio, N2_FTYPE_VOID_VPTR_SI) \
2747 N2_BUILTIN_DEF (stwio, N2_FTYPE_VOID_VPTR_SI) \
2748 N2_BUILTIN_DEF (rdctl, N2_FTYPE_SI_SI) \
2749 N2_BUILTIN_DEF (wrctl, N2_FTYPE_VOID_SI_SI)
2751 enum nios2_builtin_code
{
2752 #define N2_BUILTIN_DEF(name, ftype) NIOS2_BUILTIN_ ## name,
2754 #undef N2_BUILTIN_DEF
2755 NUM_FIXED_NIOS2_BUILTINS
2758 static const struct nios2_builtin_desc nios2_builtins
[] = {
2759 #define N2_BUILTIN_DEF(name, ftype) \
2760 { CODE_FOR_ ## name, ftype, "__builtin_" #name },
2762 #undef N2_BUILTIN_DEF
2765 /* Start/ends of FPU/custom insn builtin index ranges. */
2766 static unsigned int nios2_fpu_builtin_base
;
2767 static unsigned int nios2_custom_builtin_base
;
2768 static unsigned int nios2_custom_builtin_end
;
2770 /* Implement TARGET_INIT_BUILTINS. */
2772 nios2_init_builtins (void)
2776 /* Initialize fixed builtins. */
2777 for (i
= 0; i
< ARRAY_SIZE (nios2_builtins
); i
++)
2779 const struct nios2_builtin_desc
*d
= &nios2_builtins
[i
];
2781 add_builtin_function (d
->name
, nios2_ftype (d
->ftype
), i
,
2782 BUILT_IN_MD
, NULL
, NULL
);
2783 nios2_register_builtin_fndecl (i
, fndecl
);
2786 /* Initialize FPU builtins. */
2787 nios2_fpu_builtin_base
= ARRAY_SIZE (nios2_builtins
);
2788 nios2_init_fpu_builtins (nios2_fpu_builtin_base
);
2790 /* Initialize custom insn builtins. */
2791 nios2_custom_builtin_base
2792 = nios2_fpu_builtin_base
+ ARRAY_SIZE (nios2_fpu_insn
);
2793 nios2_custom_builtin_end
2794 = nios2_custom_builtin_base
+ NUM_CUSTOM_BUILTINS
;
2795 nios2_init_custom_builtins (nios2_custom_builtin_base
);
2798 /* Array of fndecls for TARGET_BUILTIN_DECL. */
2799 #define NIOS2_NUM_BUILTINS \
2800 (ARRAY_SIZE (nios2_builtins) + ARRAY_SIZE (nios2_fpu_insn) + NUM_CUSTOM_BUILTINS)
2801 static GTY(()) tree nios2_builtin_decls
[NIOS2_NUM_BUILTINS
];
2804 nios2_register_builtin_fndecl (unsigned code
, tree fndecl
)
2806 nios2_builtin_decls
[code
] = fndecl
;
2809 /* Implement TARGET_BUILTIN_DECL. */
2811 nios2_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
2813 gcc_assert (nios2_custom_builtin_end
== ARRAY_SIZE (nios2_builtin_decls
));
2815 if (code
>= nios2_custom_builtin_end
)
2816 return error_mark_node
;
2818 if (code
>= nios2_fpu_builtin_base
2819 && code
< nios2_custom_builtin_base
2820 && ! N2FPU_ENABLED_P (code
- nios2_fpu_builtin_base
))
2821 return error_mark_node
;
2823 return nios2_builtin_decls
[code
];
2827 /* Low-level built-in expand routine. */
2829 nios2_expand_builtin_insn (const struct nios2_builtin_desc
*d
, int n
,
2830 struct expand_operand
*ops
, bool has_target_p
)
2832 if (maybe_expand_insn (d
->icode
, n
, ops
))
2833 return has_target_p
? ops
[0].value
: const0_rtx
;
2836 error ("invalid argument to built-in function %s", d
->name
);
2837 return has_target_p
? gen_reg_rtx (ops
[0].mode
) : const0_rtx
;
2841 /* Expand ldio/stio form load-store instruction builtins. */
2843 nios2_expand_ldstio_builtin (tree exp
, rtx target
,
2844 const struct nios2_builtin_desc
*d
)
2848 struct expand_operand ops
[MAX_RECOG_OPERANDS
];
2849 machine_mode mode
= insn_data
[d
->icode
].operand
[0].mode
;
2851 addr
= expand_normal (CALL_EXPR_ARG (exp
, 0));
2852 mem
= gen_rtx_MEM (mode
, addr
);
2854 if (insn_data
[d
->icode
].operand
[0].allows_mem
)
2857 val
= expand_normal (CALL_EXPR_ARG (exp
, 1));
2858 if (CONST_INT_P (val
))
2859 val
= force_reg (mode
, gen_int_mode (INTVAL (val
), mode
));
2860 val
= simplify_gen_subreg (mode
, val
, GET_MODE (val
), 0);
2861 create_output_operand (&ops
[0], mem
, mode
);
2862 create_input_operand (&ops
[1], val
, mode
);
2863 has_target_p
= false;
2868 create_output_operand (&ops
[0], target
, mode
);
2869 create_input_operand (&ops
[1], mem
, mode
);
2870 has_target_p
= true;
2872 return nios2_expand_builtin_insn (d
, 2, ops
, has_target_p
);
2875 /* Expand rdctl/wrctl builtins. */
2877 nios2_expand_rdwrctl_builtin (tree exp
, rtx target
,
2878 const struct nios2_builtin_desc
*d
)
2880 bool has_target_p
= (insn_data
[d
->icode
].operand
[0].predicate
2881 == register_operand
);
2882 rtx ctlcode
= expand_normal (CALL_EXPR_ARG (exp
, 0));
2883 struct expand_operand ops
[MAX_RECOG_OPERANDS
];
2884 if (!rdwrctl_operand (ctlcode
, VOIDmode
))
2886 error ("Control register number must be in range 0-31 for %s",
2888 return has_target_p
? gen_reg_rtx (SImode
) : const0_rtx
;
2892 create_output_operand (&ops
[0], target
, SImode
);
2893 create_integer_operand (&ops
[1], INTVAL (ctlcode
));
2897 rtx val
= expand_normal (CALL_EXPR_ARG (exp
, 1));
2898 create_integer_operand (&ops
[0], INTVAL (ctlcode
));
2899 create_input_operand (&ops
[1], val
, SImode
);
2901 return nios2_expand_builtin_insn (d
, 2, ops
, has_target_p
);
2904 /* Implement TARGET_EXPAND_BUILTIN. Expand an expression EXP that calls
2905 a built-in function, with result going to TARGET if that's convenient
2906 (and in mode MODE if that's convenient).
2907 SUBTARGET may be used as the target for computing one of EXP's operands.
2908 IGNORE is nonzero if the value is to be ignored. */
2911 nios2_expand_builtin (tree exp
, rtx target
, rtx subtarget ATTRIBUTE_UNUSED
,
2912 machine_mode mode ATTRIBUTE_UNUSED
,
2913 int ignore ATTRIBUTE_UNUSED
)
2915 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
2916 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
2918 if (fcode
< nios2_fpu_builtin_base
)
2920 const struct nios2_builtin_desc
*d
= &nios2_builtins
[fcode
];
2924 case NIOS2_BUILTIN_sync
:
2925 emit_insn (gen_sync ());
2928 case NIOS2_BUILTIN_ldbio
:
2929 case NIOS2_BUILTIN_ldbuio
:
2930 case NIOS2_BUILTIN_ldhio
:
2931 case NIOS2_BUILTIN_ldhuio
:
2932 case NIOS2_BUILTIN_ldwio
:
2933 case NIOS2_BUILTIN_stbio
:
2934 case NIOS2_BUILTIN_sthio
:
2935 case NIOS2_BUILTIN_stwio
:
2936 return nios2_expand_ldstio_builtin (exp
, target
, d
);
2938 case NIOS2_BUILTIN_rdctl
:
2939 case NIOS2_BUILTIN_wrctl
:
2940 return nios2_expand_rdwrctl_builtin (exp
, target
, d
);
2946 else if (fcode
< nios2_custom_builtin_base
)
2947 /* FPU builtin range. */
2948 return nios2_expand_fpu_builtin (exp
, fcode
- nios2_fpu_builtin_base
,
2950 else if (fcode
< nios2_custom_builtin_end
)
2951 /* Custom insn builtin range. */
2952 return nios2_expand_custom_builtin (exp
, fcode
- nios2_custom_builtin_base
,
2958 /* Implement TARGET_INIT_LIBFUNCS. */
2960 nios2_init_libfuncs (void)
2962 /* For Linux, we have access to kernel support for atomic operations. */
2963 if (TARGET_LINUX_ABI
)
2964 init_sync_libfuncs (UNITS_PER_WORD
);
2969 /* Register a custom code use, and signal error if a conflict was found. */
2971 nios2_register_custom_code (unsigned int N
, enum nios2_ccs_code status
,
2974 gcc_assert (N
<= 255);
2976 if (status
== CCS_FPU
)
2978 if (custom_code_status
[N
] == CCS_FPU
&& index
!= custom_code_index
[N
])
2980 custom_code_conflict
= true;
2981 error ("switch %<-mcustom-%s%> conflicts with switch %<-mcustom-%s%>",
2982 N2FPU_NAME (custom_code_index
[N
]), N2FPU_NAME (index
));
2984 else if (custom_code_status
[N
] == CCS_BUILTIN_CALL
)
2986 custom_code_conflict
= true;
2987 error ("call to %<__builtin_custom_%s%> conflicts with switch "
2988 "%<-mcustom-%s%>", custom_builtin_name
[custom_code_index
[N
]],
2989 N2FPU_NAME (index
));
2992 else if (status
== CCS_BUILTIN_CALL
)
2994 if (custom_code_status
[N
] == CCS_FPU
)
2996 custom_code_conflict
= true;
2997 error ("call to %<__builtin_custom_%s%> conflicts with switch "
2998 "%<-mcustom-%s%>", custom_builtin_name
[index
],
2999 N2FPU_NAME (custom_code_index
[N
]));
3003 /* Note that code conflicts between different __builtin_custom_xnxx
3004 calls are not checked. */
3010 custom_code_status
[N
] = status
;
3011 custom_code_index
[N
] = index
;
3014 /* Mark a custom code as not in use. */
3016 nios2_deregister_custom_code (unsigned int N
)
3020 custom_code_status
[N
] = CCS_UNUSED
;
3021 custom_code_index
[N
] = 0;
3025 /* Target attributes can affect per-function option state, so we need to
3026 save/restore the custom code tracking info using the
3027 TARGET_OPTION_SAVE/TARGET_OPTION_RESTORE hooks. */
3030 nios2_option_save (struct cl_target_option
*ptr
,
3031 struct gcc_options
*opts ATTRIBUTE_UNUSED
)
3034 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
3035 ptr
->saved_fpu_custom_code
[i
] = N2FPU_N (i
);
3036 memcpy (ptr
->saved_custom_code_status
, custom_code_status
,
3037 sizeof (custom_code_status
));
3038 memcpy (ptr
->saved_custom_code_index
, custom_code_index
,
3039 sizeof (custom_code_index
));
3043 nios2_option_restore (struct gcc_options
*opts ATTRIBUTE_UNUSED
,
3044 struct cl_target_option
*ptr
)
3047 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
3048 N2FPU_N (i
) = ptr
->saved_fpu_custom_code
[i
];
3049 memcpy (custom_code_status
, ptr
->saved_custom_code_status
,
3050 sizeof (custom_code_status
));
3051 memcpy (custom_code_index
, ptr
->saved_custom_code_index
,
3052 sizeof (custom_code_index
));
3055 /* Inner function to process the attribute((target(...))), take an argument and
3056 set the current options from the argument. If we have a list, recursively
3057 go over the list. */
3060 nios2_valid_target_attribute_rec (tree args
)
3062 if (TREE_CODE (args
) == TREE_LIST
)
3065 for (; args
; args
= TREE_CHAIN (args
))
3066 if (TREE_VALUE (args
)
3067 && !nios2_valid_target_attribute_rec (TREE_VALUE (args
)))
3071 else if (TREE_CODE (args
) == STRING_CST
)
3073 char *argstr
= ASTRDUP (TREE_STRING_POINTER (args
));
3074 while (argstr
&& *argstr
!= '\0')
3076 bool no_opt
= false, end_p
= false;
3077 char *eq
= NULL
, *p
;
3078 while (ISSPACE (*argstr
))
3081 while (*p
!= '\0' && *p
!= ',')
3083 if (!eq
&& *p
== '=')
3093 if (!strncmp (argstr
, "no-", 3))
3098 if (!strncmp (argstr
, "custom-fpu-cfg", 14))
3103 error ("custom-fpu-cfg option does not support %<no-%>");
3108 error ("custom-fpu-cfg option requires configuration"
3112 /* Increment and skip whitespace. */
3113 while (ISSPACE (*(++eq
))) ;
3114 /* Decrement and skip to before any trailing whitespace. */
3115 while (ISSPACE (*(--end_eq
))) ;
3117 nios2_handle_custom_fpu_cfg (eq
, end_eq
+ 1, true);
3119 else if (!strncmp (argstr
, "custom-", 7))
3123 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
3124 if (!strncmp (argstr
+ 7, N2FPU_NAME (i
),
3125 strlen (N2FPU_NAME (i
))))
3137 error ("%<no-custom-%s%> does not accept arguments",
3141 /* Disable option by setting to -1. */
3142 nios2_deregister_custom_code (N2FPU_N (code
));
3143 N2FPU_N (code
) = -1;
3149 while (ISSPACE (*(++eq
))) ;
3152 error ("%<custom-%s=%> requires argument",
3156 for (t
= eq
; t
!= p
; ++t
)
3162 error ("`custom-%s=' argument requires "
3163 "numeric digits", N2FPU_NAME (code
));
3167 /* Set option to argument. */
3168 N2FPU_N (code
) = atoi (eq
);
3169 nios2_handle_custom_fpu_insn_option (code
);
3174 error ("%<custom-%s=%> is not recognised as FPU instruction",
3181 error ("%<%s%> is unknown", argstr
);
3196 /* Return a TARGET_OPTION_NODE tree of the target options listed or NULL. */
3199 nios2_valid_target_attribute_tree (tree args
)
3201 if (!nios2_valid_target_attribute_rec (args
))
3203 nios2_custom_check_insns ();
3204 return build_target_option_node (&global_options
);
3207 /* Hook to validate attribute((target("string"))). */
3210 nios2_valid_target_attribute_p (tree fndecl
, tree
ARG_UNUSED (name
),
3211 tree args
, int ARG_UNUSED (flags
))
3213 struct cl_target_option cur_target
;
3215 tree old_optimize
= build_optimization_node (&global_options
);
3216 tree new_target
, new_optimize
;
3217 tree func_optimize
= DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl
);
3219 /* If the function changed the optimization levels as well as setting target
3220 options, start with the optimizations specified. */
3221 if (func_optimize
&& func_optimize
!= old_optimize
)
3222 cl_optimization_restore (&global_options
,
3223 TREE_OPTIMIZATION (func_optimize
));
3225 /* The target attributes may also change some optimization flags, so update
3226 the optimization options if necessary. */
3227 cl_target_option_save (&cur_target
, &global_options
);
3228 new_target
= nios2_valid_target_attribute_tree (args
);
3229 new_optimize
= build_optimization_node (&global_options
);
3236 DECL_FUNCTION_SPECIFIC_TARGET (fndecl
) = new_target
;
3238 if (old_optimize
!= new_optimize
)
3239 DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl
) = new_optimize
;
3242 cl_target_option_restore (&global_options
, &cur_target
);
3244 if (old_optimize
!= new_optimize
)
3245 cl_optimization_restore (&global_options
,
3246 TREE_OPTIMIZATION (old_optimize
));
3250 /* Remember the last target of nios2_set_current_function. */
3251 static GTY(()) tree nios2_previous_fndecl
;
3253 /* Establish appropriate back-end context for processing the function
3254 FNDECL. The argument might be NULL to indicate processing at top
3255 level, outside of any function scope. */
3257 nios2_set_current_function (tree fndecl
)
3259 tree old_tree
= (nios2_previous_fndecl
3260 ? DECL_FUNCTION_SPECIFIC_TARGET (nios2_previous_fndecl
)
3263 tree new_tree
= (fndecl
3264 ? DECL_FUNCTION_SPECIFIC_TARGET (fndecl
)
3267 if (fndecl
&& fndecl
!= nios2_previous_fndecl
)
3269 nios2_previous_fndecl
= fndecl
;
3270 if (old_tree
== new_tree
)
3275 cl_target_option_restore (&global_options
,
3276 TREE_TARGET_OPTION (new_tree
));
3282 struct cl_target_option
*def
3283 = TREE_TARGET_OPTION (target_option_current_node
);
3285 cl_target_option_restore (&global_options
, def
);
3291 /* Hook to validate the current #pragma GCC target and set the FPU custom
3292 code option state. If ARGS is NULL, then POP_TARGET is used to reset
3295 nios2_pragma_target_parse (tree args
, tree pop_target
)
3300 cur_tree
= ((pop_target
)
3302 : target_option_default_node
);
3303 cl_target_option_restore (&global_options
,
3304 TREE_TARGET_OPTION (cur_tree
));
3308 cur_tree
= nios2_valid_target_attribute_tree (args
);
3313 target_option_current_node
= cur_tree
;
3317 /* Implement TARGET_MERGE_DECL_ATTRIBUTES.
3318 We are just using this hook to add some additional error checking to
3319 the default behavior. GCC does not provide a target hook for merging
3320 the target options, and only correctly handles merging empty vs non-empty
3321 option data; see merge_decls() in c-decl.c.
3322 So here we require either that at least one of the decls has empty
3323 target options, or that the target options/data be identical. */
3325 nios2_merge_decl_attributes (tree olddecl
, tree newdecl
)
3327 tree oldopts
= lookup_attribute ("target", DECL_ATTRIBUTES (olddecl
));
3328 tree newopts
= lookup_attribute ("target", DECL_ATTRIBUTES (newdecl
));
3329 if (newopts
&& oldopts
&& newopts
!= oldopts
)
3331 tree oldtree
= DECL_FUNCTION_SPECIFIC_TARGET (olddecl
);
3332 tree newtree
= DECL_FUNCTION_SPECIFIC_TARGET (newdecl
);
3333 if (oldtree
&& newtree
&& oldtree
!= newtree
)
3335 struct cl_target_option
*olddata
= TREE_TARGET_OPTION (oldtree
);
3336 struct cl_target_option
*newdata
= TREE_TARGET_OPTION (newtree
);
3337 if (olddata
!= newdata
3338 && memcmp (olddata
, newdata
, sizeof (struct cl_target_option
)))
3339 error ("%qE redeclared with conflicting %qs attributes",
3340 DECL_NAME (newdecl
), "target");
3343 return merge_attributes (DECL_ATTRIBUTES (olddecl
),
3344 DECL_ATTRIBUTES (newdecl
));
3347 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
3349 nios2_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3350 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3353 rtx this_rtx
, funexp
;
3356 /* Pretend to be a post-reload pass while generating rtl. */
3357 reload_completed
= 1;
3360 nios2_load_pic_register ();
3362 /* Mark the end of the (empty) prologue. */
3363 emit_note (NOTE_INSN_PROLOGUE_END
);
3365 /* Find the "this" pointer. If the function returns a structure,
3366 the structure return pointer is in $5. */
3367 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3368 this_rtx
= gen_rtx_REG (Pmode
, FIRST_ARG_REGNO
+ 1);
3370 this_rtx
= gen_rtx_REG (Pmode
, FIRST_ARG_REGNO
);
3372 /* Add DELTA to THIS_RTX. */
3373 nios2_emit_add_constant (this_rtx
, delta
);
3375 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
3380 tmp
= gen_rtx_REG (Pmode
, 2);
3381 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, this_rtx
));
3382 nios2_emit_add_constant (tmp
, vcall_offset
);
3383 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, tmp
));
3384 emit_insn (gen_add2_insn (this_rtx
, tmp
));
3387 /* Generate a tail call to the target function. */
3388 if (!TREE_USED (function
))
3390 assemble_external (function
);
3391 TREE_USED (function
) = 1;
3393 funexp
= XEXP (DECL_RTL (function
), 0);
3394 /* Function address needs to be constructed under PIC,
3395 provide r2 to use here. */
3396 nios2_adjust_call_address (&funexp
, gen_rtx_REG (Pmode
, 2));
3397 insn
= emit_call_insn (gen_sibcall_internal (funexp
, const0_rtx
));
3398 SIBLING_CALL_P (insn
) = 1;
3400 /* Run just enough of rest_of_compilation to get the insns emitted.
3401 There's not really enough bulk here to make other passes such as
3402 instruction scheduling worth while. Note that use_thunk calls
3403 assemble_start_function and assemble_end_function. */
3404 insn
= get_insns ();
3405 shorten_branches (insn
);
3406 final_start_function (insn
, file
, 1);
3407 final (insn
, file
, 1);
3408 final_end_function ();
3410 /* Stop pretending to be a post-reload pass. */
3411 reload_completed
= 0;
3415 /* Initialize the GCC target structure. */
3416 #undef TARGET_ASM_FUNCTION_PROLOGUE
3417 #define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue
3419 #undef TARGET_IN_SMALL_DATA_P
3420 #define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p
3422 #undef TARGET_SECTION_TYPE_FLAGS
3423 #define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags
3425 #undef TARGET_INIT_BUILTINS
3426 #define TARGET_INIT_BUILTINS nios2_init_builtins
3427 #undef TARGET_EXPAND_BUILTIN
3428 #define TARGET_EXPAND_BUILTIN nios2_expand_builtin
3429 #undef TARGET_BUILTIN_DECL
3430 #define TARGET_BUILTIN_DECL nios2_builtin_decl
3432 #undef TARGET_INIT_LIBFUNCS
3433 #define TARGET_INIT_LIBFUNCS nios2_init_libfuncs
3435 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
3436 #define TARGET_FUNCTION_OK_FOR_SIBCALL hook_bool_tree_tree_true
3438 #undef TARGET_CAN_ELIMINATE
3439 #define TARGET_CAN_ELIMINATE nios2_can_eliminate
3441 #undef TARGET_FUNCTION_ARG
3442 #define TARGET_FUNCTION_ARG nios2_function_arg
3444 #undef TARGET_FUNCTION_ARG_ADVANCE
3445 #define TARGET_FUNCTION_ARG_ADVANCE nios2_function_arg_advance
3447 #undef TARGET_ARG_PARTIAL_BYTES
3448 #define TARGET_ARG_PARTIAL_BYTES nios2_arg_partial_bytes
3450 #undef TARGET_TRAMPOLINE_INIT
3451 #define TARGET_TRAMPOLINE_INIT nios2_trampoline_init
3453 #undef TARGET_FUNCTION_VALUE
3454 #define TARGET_FUNCTION_VALUE nios2_function_value
3456 #undef TARGET_LIBCALL_VALUE
3457 #define TARGET_LIBCALL_VALUE nios2_libcall_value
3459 #undef TARGET_FUNCTION_VALUE_REGNO_P
3460 #define TARGET_FUNCTION_VALUE_REGNO_P nios2_function_value_regno_p
3462 #undef TARGET_RETURN_IN_MEMORY
3463 #define TARGET_RETURN_IN_MEMORY nios2_return_in_memory
3465 #undef TARGET_PROMOTE_PROTOTYPES
3466 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
3468 #undef TARGET_SETUP_INCOMING_VARARGS
3469 #define TARGET_SETUP_INCOMING_VARARGS nios2_setup_incoming_varargs
3471 #undef TARGET_MUST_PASS_IN_STACK
3472 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
3474 #undef TARGET_LEGITIMATE_CONSTANT_P
3475 #define TARGET_LEGITIMATE_CONSTANT_P nios2_legitimate_constant_p
3477 #undef TARGET_LEGITIMIZE_ADDRESS
3478 #define TARGET_LEGITIMIZE_ADDRESS nios2_legitimize_address
3480 #undef TARGET_DELEGITIMIZE_ADDRESS
3481 #define TARGET_DELEGITIMIZE_ADDRESS nios2_delegitimize_address
3483 #undef TARGET_LEGITIMATE_ADDRESS_P
3484 #define TARGET_LEGITIMATE_ADDRESS_P nios2_legitimate_address_p
3486 #undef TARGET_PREFERRED_RELOAD_CLASS
3487 #define TARGET_PREFERRED_RELOAD_CLASS nios2_preferred_reload_class
3489 #undef TARGET_RTX_COSTS
3490 #define TARGET_RTX_COSTS nios2_rtx_costs
3492 #undef TARGET_HAVE_TLS
3493 #define TARGET_HAVE_TLS TARGET_LINUX_ABI
3495 #undef TARGET_CANNOT_FORCE_CONST_MEM
3496 #define TARGET_CANNOT_FORCE_CONST_MEM nios2_cannot_force_const_mem
3498 #undef TARGET_ASM_OUTPUT_DWARF_DTPREL
3499 #define TARGET_ASM_OUTPUT_DWARF_DTPREL nios2_output_dwarf_dtprel
3501 #undef TARGET_PRINT_OPERAND
3502 #define TARGET_PRINT_OPERAND nios2_print_operand
3504 #undef TARGET_PRINT_OPERAND_ADDRESS
3505 #define TARGET_PRINT_OPERAND_ADDRESS nios2_print_operand_address
3507 #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
3508 #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA nios2_output_addr_const_extra
3510 #undef TARGET_ASM_FILE_END
3511 #define TARGET_ASM_FILE_END nios2_asm_file_end
3513 #undef TARGET_OPTION_OVERRIDE
3514 #define TARGET_OPTION_OVERRIDE nios2_option_override
3516 #undef TARGET_OPTION_SAVE
3517 #define TARGET_OPTION_SAVE nios2_option_save
3519 #undef TARGET_OPTION_RESTORE
3520 #define TARGET_OPTION_RESTORE nios2_option_restore
3522 #undef TARGET_SET_CURRENT_FUNCTION
3523 #define TARGET_SET_CURRENT_FUNCTION nios2_set_current_function
3525 #undef TARGET_OPTION_VALID_ATTRIBUTE_P
3526 #define TARGET_OPTION_VALID_ATTRIBUTE_P nios2_valid_target_attribute_p
3528 #undef TARGET_OPTION_PRAGMA_PARSE
3529 #define TARGET_OPTION_PRAGMA_PARSE nios2_pragma_target_parse
3531 #undef TARGET_MERGE_DECL_ATTRIBUTES
3532 #define TARGET_MERGE_DECL_ATTRIBUTES nios2_merge_decl_attributes
3534 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3535 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
3536 hook_bool_const_tree_hwi_hwi_const_tree_true
3538 #undef TARGET_ASM_OUTPUT_MI_THUNK
3539 #define TARGET_ASM_OUTPUT_MI_THUNK nios2_asm_output_mi_thunk
3541 struct gcc_target targetm
= TARGET_INITIALIZER
;
3543 #include "gt-nios2.h"