1 /* Target machine subroutines for Altera Nios II.
2 Copyright (C) 2012-2015 Free Software Foundation, Inc.
3 Contributed by Jonah Graham (jgraham@altera.com),
4 Will Reece (wreece@altera.com), and Jeff DaSilva (jdasilva@altera.com).
5 Contributed by Mentor Graphics, Inc.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published
11 by the Free Software Foundation; either version 3, or (at your
12 option) any later version.
14 GCC is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
17 License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3. If not see
21 <http://www.gnu.org/licenses/>. */
25 #include "coretypes.h"
31 #include "fold-const.h"
33 #include "hard-reg-set.h"
34 #include "insn-config.h"
35 #include "conditions.h"
37 #include "insn-attr.h"
49 #include "insn-codes.h"
52 #include "dominance.h"
58 #include "cfgcleanup.h"
59 #include "basic-block.h"
60 #include "diagnostic-core.h"
64 #include "langhooks.h"
68 #include "stor-layout.h"
71 #include "target-def.h"
73 /* Forward function declarations. */
74 static bool prologue_saved_reg_p (unsigned);
75 static void nios2_load_pic_register (void);
76 static void nios2_register_custom_code (unsigned int, enum nios2_ccs_code
, int);
77 static const char *nios2_unspec_reloc_name (int);
78 static void nios2_register_builtin_fndecl (unsigned, tree
);
80 /* Threshold for data being put into the small data/bss area, instead
81 of the normal data area (references to the small data/bss area take
82 1 instruction, and use the global pointer, references to the normal
83 data area takes 2 instructions). */
84 unsigned HOST_WIDE_INT nios2_section_threshold
= NIOS2_DEFAULT_GVALUE
;
86 struct GTY (()) machine_function
88 /* Current frame information, to be filled in by nios2_compute_frame_layout
89 with register save masks, and offsets for the current function. */
91 /* Mask of registers to save. */
92 unsigned int save_mask
;
93 /* Number of bytes that the entire frame takes up. */
95 /* Number of bytes that variables take up. */
97 /* Number of bytes that outgoing arguments take up. */
99 /* Number of bytes needed to store registers in frame. */
101 /* Offset from new stack pointer to store registers. */
102 int save_regs_offset
;
103 /* Offset from save_regs_offset to store frame pointer register. */
105 /* != 0 if frame layout already calculated. */
109 /* State to track the assignment of custom codes to FPU/custom builtins. */
110 static enum nios2_ccs_code custom_code_status
[256];
111 static int custom_code_index
[256];
112 /* Set to true if any conflicts (re-use of a code between 0-255) are found. */
113 static bool custom_code_conflict
= false;
116 /* Definition of builtin function types for nios2. */
120 N2_FTYPE(1, (VOID)) \
121 N2_FTYPE(2, (DF, DF)) \
122 N2_FTYPE(3, (DF, DF, DF)) \
123 N2_FTYPE(2, (DF, SF)) \
124 N2_FTYPE(2, (DF, SI)) \
125 N2_FTYPE(2, (DF, UI)) \
126 N2_FTYPE(2, (SF, DF)) \
127 N2_FTYPE(2, (SF, SF)) \
128 N2_FTYPE(3, (SF, SF, SF)) \
129 N2_FTYPE(2, (SF, SI)) \
130 N2_FTYPE(2, (SF, UI)) \
131 N2_FTYPE(2, (SI, CVPTR)) \
132 N2_FTYPE(2, (SI, DF)) \
133 N2_FTYPE(3, (SI, DF, DF)) \
134 N2_FTYPE(2, (SI, SF)) \
135 N2_FTYPE(3, (SI, SF, SF)) \
136 N2_FTYPE(2, (SI, SI)) \
137 N2_FTYPE(2, (UI, CVPTR)) \
138 N2_FTYPE(2, (UI, DF)) \
139 N2_FTYPE(2, (UI, SF)) \
140 N2_FTYPE(2, (VOID, DF)) \
141 N2_FTYPE(2, (VOID, SF)) \
142 N2_FTYPE(3, (VOID, SI, SI)) \
143 N2_FTYPE(3, (VOID, VPTR, SI))
145 #define N2_FTYPE_OP1(R) N2_FTYPE_ ## R ## _VOID
146 #define N2_FTYPE_OP2(R, A1) N2_FTYPE_ ## R ## _ ## A1
147 #define N2_FTYPE_OP3(R, A1, A2) N2_FTYPE_ ## R ## _ ## A1 ## _ ## A2
149 /* Expand ftcode enumeration. */
151 #define N2_FTYPE(N,ARGS) N2_FTYPE_OP ## N ARGS,
157 /* Return the tree function type, based on the ftcode. */
159 nios2_ftype (enum nios2_ftcode ftcode
)
161 static tree types
[(int) N2_FTYPE_MAX
];
163 tree N2_TYPE_SF
= float_type_node
;
164 tree N2_TYPE_DF
= double_type_node
;
165 tree N2_TYPE_SI
= integer_type_node
;
166 tree N2_TYPE_UI
= unsigned_type_node
;
167 tree N2_TYPE_VOID
= void_type_node
;
169 static const_tree N2_TYPE_CVPTR
, N2_TYPE_VPTR
;
172 /* const volatile void *. */
174 = build_pointer_type (build_qualified_type (void_type_node
,
176 | TYPE_QUAL_VOLATILE
)));
177 /* volatile void *. */
179 = build_pointer_type (build_qualified_type (void_type_node
,
180 TYPE_QUAL_VOLATILE
));
182 if (types
[(int) ftcode
] == NULL_TREE
)
185 #define N2_FTYPE_ARGS1(R) N2_TYPE_ ## R
186 #define N2_FTYPE_ARGS2(R,A1) N2_TYPE_ ## R, N2_TYPE_ ## A1
187 #define N2_FTYPE_ARGS3(R,A1,A2) N2_TYPE_ ## R, N2_TYPE_ ## A1, N2_TYPE_ ## A2
188 #define N2_FTYPE(N,ARGS) \
189 case N2_FTYPE_OP ## N ARGS: \
190 types[(int) ftcode] \
191 = build_function_type_list (N2_FTYPE_ARGS ## N ARGS, NULL_TREE); \
195 default: gcc_unreachable ();
197 return types
[(int) ftcode
];
201 /* Definition of FPU instruction descriptions. */
203 struct nios2_fpu_insn_info
206 int num_operands
, *optvar
;
209 #define N2F_DFREQ 0x2
210 #define N2F_UNSAFE 0x4
211 #define N2F_FINITE 0x8
212 #define N2F_NO_ERRNO 0x10
214 enum insn_code icode
;
215 enum nios2_ftcode ftcode
;
218 /* Base macro for defining FPU instructions. */
219 #define N2FPU_INSN_DEF_BASE(insn, nop, flags, icode, args) \
220 { #insn, nop, &nios2_custom_ ## insn, OPT_mcustom_##insn##_, \
221 OPT_mno_custom_##insn, flags, CODE_FOR_ ## icode, \
222 N2_FTYPE_OP ## nop args }
224 /* Arithmetic and math functions; 2 or 3 operand FP operations. */
225 #define N2FPU_OP2(mode) (mode, mode)
226 #define N2FPU_OP3(mode) (mode, mode, mode)
227 #define N2FPU_INSN_DEF(code, icode, nop, flags, m, M) \
228 N2FPU_INSN_DEF_BASE (f ## code ## m, nop, flags, \
229 icode ## m ## f ## nop, N2FPU_OP ## nop (M ## F))
230 #define N2FPU_INSN_SF(code, nop, flags) \
231 N2FPU_INSN_DEF (code, code, nop, flags, s, S)
232 #define N2FPU_INSN_DF(code, nop, flags) \
233 N2FPU_INSN_DEF (code, code, nop, flags | N2F_DF, d, D)
235 /* Compare instructions, 3 operand FP operation with a SI result. */
236 #define N2FPU_CMP_DEF(code, flags, m, M) \
237 N2FPU_INSN_DEF_BASE (fcmp ## code ## m, 3, flags, \
238 nios2_s ## code ## m ## f, (SI, M ## F, M ## F))
239 #define N2FPU_CMP_SF(code) N2FPU_CMP_DEF (code, 0, s, S)
240 #define N2FPU_CMP_DF(code) N2FPU_CMP_DEF (code, N2F_DF, d, D)
242 /* The order of definition needs to be maintained consistent with
243 enum n2fpu_code in nios2-opts.h. */
244 struct nios2_fpu_insn_info nios2_fpu_insn
[] =
246 /* Single precision instructions. */
247 N2FPU_INSN_SF (add
, 3, 0),
248 N2FPU_INSN_SF (sub
, 3, 0),
249 N2FPU_INSN_SF (mul
, 3, 0),
250 N2FPU_INSN_SF (div
, 3, 0),
251 /* Due to textual difference between min/max and smin/smax. */
252 N2FPU_INSN_DEF (min
, smin
, 3, N2F_FINITE
, s
, S
),
253 N2FPU_INSN_DEF (max
, smax
, 3, N2F_FINITE
, s
, S
),
254 N2FPU_INSN_SF (neg
, 2, 0),
255 N2FPU_INSN_SF (abs
, 2, 0),
256 N2FPU_INSN_SF (sqrt
, 2, 0),
257 N2FPU_INSN_SF (sin
, 2, N2F_UNSAFE
),
258 N2FPU_INSN_SF (cos
, 2, N2F_UNSAFE
),
259 N2FPU_INSN_SF (tan
, 2, N2F_UNSAFE
),
260 N2FPU_INSN_SF (atan
, 2, N2F_UNSAFE
),
261 N2FPU_INSN_SF (exp
, 2, N2F_UNSAFE
),
262 N2FPU_INSN_SF (log
, 2, N2F_UNSAFE
),
263 /* Single precision compares. */
264 N2FPU_CMP_SF (eq
), N2FPU_CMP_SF (ne
),
265 N2FPU_CMP_SF (lt
), N2FPU_CMP_SF (le
),
266 N2FPU_CMP_SF (gt
), N2FPU_CMP_SF (ge
),
268 /* Double precision instructions. */
269 N2FPU_INSN_DF (add
, 3, 0),
270 N2FPU_INSN_DF (sub
, 3, 0),
271 N2FPU_INSN_DF (mul
, 3, 0),
272 N2FPU_INSN_DF (div
, 3, 0),
273 /* Due to textual difference between min/max and smin/smax. */
274 N2FPU_INSN_DEF (min
, smin
, 3, N2F_FINITE
, d
, D
),
275 N2FPU_INSN_DEF (max
, smax
, 3, N2F_FINITE
, d
, D
),
276 N2FPU_INSN_DF (neg
, 2, 0),
277 N2FPU_INSN_DF (abs
, 2, 0),
278 N2FPU_INSN_DF (sqrt
, 2, 0),
279 N2FPU_INSN_DF (sin
, 2, N2F_UNSAFE
),
280 N2FPU_INSN_DF (cos
, 2, N2F_UNSAFE
),
281 N2FPU_INSN_DF (tan
, 2, N2F_UNSAFE
),
282 N2FPU_INSN_DF (atan
, 2, N2F_UNSAFE
),
283 N2FPU_INSN_DF (exp
, 2, N2F_UNSAFE
),
284 N2FPU_INSN_DF (log
, 2, N2F_UNSAFE
),
285 /* Double precision compares. */
286 N2FPU_CMP_DF (eq
), N2FPU_CMP_DF (ne
),
287 N2FPU_CMP_DF (lt
), N2FPU_CMP_DF (le
),
288 N2FPU_CMP_DF (gt
), N2FPU_CMP_DF (ge
),
290 /* Conversion instructions. */
291 N2FPU_INSN_DEF_BASE (floatis
, 2, 0, floatsisf2
, (SF
, SI
)),
292 N2FPU_INSN_DEF_BASE (floatus
, 2, 0, floatunssisf2
, (SF
, UI
)),
293 N2FPU_INSN_DEF_BASE (floatid
, 2, 0, floatsidf2
, (DF
, SI
)),
294 N2FPU_INSN_DEF_BASE (floatud
, 2, 0, floatunssidf2
, (DF
, UI
)),
295 N2FPU_INSN_DEF_BASE (round
, 2, N2F_NO_ERRNO
, lroundsfsi2
, (SI
, SF
)),
296 N2FPU_INSN_DEF_BASE (fixsi
, 2, 0, fix_truncsfsi2
, (SI
, SF
)),
297 N2FPU_INSN_DEF_BASE (fixsu
, 2, 0, fixuns_truncsfsi2
, (UI
, SF
)),
298 N2FPU_INSN_DEF_BASE (fixdi
, 2, 0, fix_truncdfsi2
, (SI
, DF
)),
299 N2FPU_INSN_DEF_BASE (fixdu
, 2, 0, fixuns_truncdfsi2
, (UI
, DF
)),
300 N2FPU_INSN_DEF_BASE (fextsd
, 2, 0, extendsfdf2
, (DF
, SF
)),
301 N2FPU_INSN_DEF_BASE (ftruncds
, 2, 0, truncdfsf2
, (SF
, DF
)),
303 /* X, Y access instructions. */
304 N2FPU_INSN_DEF_BASE (fwrx
, 2, N2F_DFREQ
, nios2_fwrx
, (VOID
, DF
)),
305 N2FPU_INSN_DEF_BASE (fwry
, 2, N2F_DFREQ
, nios2_fwry
, (VOID
, SF
)),
306 N2FPU_INSN_DEF_BASE (frdxlo
, 1, N2F_DFREQ
, nios2_frdxlo
, (SF
)),
307 N2FPU_INSN_DEF_BASE (frdxhi
, 1, N2F_DFREQ
, nios2_frdxhi
, (SF
)),
308 N2FPU_INSN_DEF_BASE (frdy
, 1, N2F_DFREQ
, nios2_frdy
, (SF
))
311 /* Some macros for ease of access. */
312 #define N2FPU(code) nios2_fpu_insn[(int) code]
313 #define N2FPU_ENABLED_P(code) (N2FPU_N(code) >= 0)
314 #define N2FPU_N(code) (*N2FPU(code).optvar)
315 #define N2FPU_NAME(code) (N2FPU(code).name)
316 #define N2FPU_ICODE(code) (N2FPU(code).icode)
317 #define N2FPU_FTCODE(code) (N2FPU(code).ftcode)
318 #define N2FPU_FINITE_P(code) (N2FPU(code).flags & N2F_FINITE)
319 #define N2FPU_UNSAFE_P(code) (N2FPU(code).flags & N2F_UNSAFE)
320 #define N2FPU_NO_ERRNO_P(code) (N2FPU(code).flags & N2F_NO_ERRNO)
321 #define N2FPU_DOUBLE_P(code) (N2FPU(code).flags & N2F_DF)
322 #define N2FPU_DOUBLE_REQUIRED_P(code) (N2FPU(code).flags & N2F_DFREQ)
324 /* Same as above, but for cases where using only the op part is shorter. */
325 #define N2FPU_OP(op) N2FPU(n2fpu_ ## op)
326 #define N2FPU_OP_NAME(op) N2FPU_NAME(n2fpu_ ## op)
327 #define N2FPU_OP_ENABLED_P(op) N2FPU_ENABLED_P(n2fpu_ ## op)
329 /* Export the FPU insn enabled predicate to nios2.md. */
331 nios2_fpu_insn_enabled (enum n2fpu_code code
)
333 return N2FPU_ENABLED_P (code
);
336 /* Return true if COND comparison for mode MODE is enabled under current
340 nios2_fpu_compare_enabled (enum rtx_code cond
, machine_mode mode
)
345 case EQ
: return N2FPU_OP_ENABLED_P (fcmpeqs
);
346 case NE
: return N2FPU_OP_ENABLED_P (fcmpnes
);
347 case GT
: return N2FPU_OP_ENABLED_P (fcmpgts
);
348 case GE
: return N2FPU_OP_ENABLED_P (fcmpges
);
349 case LT
: return N2FPU_OP_ENABLED_P (fcmplts
);
350 case LE
: return N2FPU_OP_ENABLED_P (fcmples
);
353 else if (mode
== DFmode
)
356 case EQ
: return N2FPU_OP_ENABLED_P (fcmpeqd
);
357 case NE
: return N2FPU_OP_ENABLED_P (fcmpned
);
358 case GT
: return N2FPU_OP_ENABLED_P (fcmpgtd
);
359 case GE
: return N2FPU_OP_ENABLED_P (fcmpged
);
360 case LT
: return N2FPU_OP_ENABLED_P (fcmpltd
);
361 case LE
: return N2FPU_OP_ENABLED_P (fcmpled
);
367 /* Stack layout and calling conventions. */
369 #define NIOS2_STACK_ALIGN(LOC) \
370 (((LOC) + ((PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) - 1)) \
371 & ~((PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) - 1))
373 /* Return the bytes needed to compute the frame pointer from the current
376 nios2_compute_frame_layout (void)
379 unsigned int save_mask
= 0;
385 if (cfun
->machine
->initialized
)
386 return cfun
->machine
->total_size
;
388 var_size
= NIOS2_STACK_ALIGN (get_frame_size ());
389 out_args_size
= NIOS2_STACK_ALIGN (crtl
->outgoing_args_size
);
390 total_size
= var_size
+ out_args_size
;
392 /* Calculate space needed for gp registers. */
394 for (regno
= 0; regno
<= LAST_GP_REG
; regno
++)
395 if (prologue_saved_reg_p (regno
))
397 save_mask
|= 1 << regno
;
401 /* If we call eh_return, we need to save the EH data registers. */
402 if (crtl
->calls_eh_return
)
407 for (i
= 0; (r
= EH_RETURN_DATA_REGNO (i
)) != INVALID_REGNUM
; i
++)
408 if (!(save_mask
& (1 << r
)))
415 cfun
->machine
->fp_save_offset
= 0;
416 if (save_mask
& (1 << HARD_FRAME_POINTER_REGNUM
))
418 int fp_save_offset
= 0;
419 for (regno
= 0; regno
< HARD_FRAME_POINTER_REGNUM
; regno
++)
420 if (save_mask
& (1 << regno
))
423 cfun
->machine
->fp_save_offset
= fp_save_offset
;
426 save_reg_size
= NIOS2_STACK_ALIGN (save_reg_size
);
427 total_size
+= save_reg_size
;
428 total_size
+= NIOS2_STACK_ALIGN (crtl
->args
.pretend_args_size
);
430 /* Save other computed information. */
431 cfun
->machine
->save_mask
= save_mask
;
432 cfun
->machine
->total_size
= total_size
;
433 cfun
->machine
->var_size
= var_size
;
434 cfun
->machine
->args_size
= out_args_size
;
435 cfun
->machine
->save_reg_size
= save_reg_size
;
436 cfun
->machine
->initialized
= reload_completed
;
437 cfun
->machine
->save_regs_offset
= out_args_size
+ var_size
;
442 /* Generate save/restore of register REGNO at SP + OFFSET. Used by the
443 prologue/epilogue expand routines. */
445 save_reg (int regno
, unsigned offset
)
447 rtx reg
= gen_rtx_REG (SImode
, regno
);
448 rtx addr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
449 gen_int_mode (offset
, Pmode
));
450 rtx insn
= emit_move_insn (gen_frame_mem (Pmode
, addr
), reg
);
451 RTX_FRAME_RELATED_P (insn
) = 1;
455 restore_reg (int regno
, unsigned offset
)
457 rtx reg
= gen_rtx_REG (SImode
, regno
);
458 rtx addr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
459 gen_int_mode (offset
, Pmode
));
460 rtx insn
= emit_move_insn (reg
, gen_frame_mem (Pmode
, addr
));
461 /* Tag epilogue unwind note. */
462 add_reg_note (insn
, REG_CFA_RESTORE
, reg
);
463 RTX_FRAME_RELATED_P (insn
) = 1;
466 /* Emit conditional trap for checking stack limit. */
468 nios2_emit_stack_limit_check (void)
470 if (REG_P (stack_limit_rtx
))
471 emit_insn (gen_ctrapsi4 (gen_rtx_LTU (VOIDmode
, stack_pointer_rtx
,
473 stack_pointer_rtx
, stack_limit_rtx
, GEN_INT (3)));
475 sorry ("only register based stack limit is supported");
478 /* Temp regno used inside prologue/epilogue. */
479 #define TEMP_REG_NUM 8
482 nios2_emit_add_constant (rtx reg
, HOST_WIDE_INT immed
)
485 if (SMALL_INT (immed
))
486 insn
= emit_insn (gen_add2_insn (reg
, gen_int_mode (immed
, Pmode
)));
489 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
490 emit_move_insn (tmp
, gen_int_mode (immed
, Pmode
));
491 insn
= emit_insn (gen_add2_insn (reg
, tmp
));
497 nios2_expand_prologue (void)
500 int total_frame_size
, save_offset
;
501 int sp_offset
; /* offset from base_reg to final stack value. */
502 int save_regs_base
; /* offset from base_reg to register save area. */
505 total_frame_size
= nios2_compute_frame_layout ();
507 if (flag_stack_usage_info
)
508 current_function_static_stack_size
= total_frame_size
;
510 /* Decrement the stack pointer. */
511 if (!SMALL_INT (total_frame_size
))
513 /* We need an intermediary point, this will point at the spill block. */
515 (gen_add2_insn (stack_pointer_rtx
,
516 gen_int_mode (cfun
->machine
->save_regs_offset
517 - total_frame_size
, Pmode
)));
518 RTX_FRAME_RELATED_P (insn
) = 1;
520 sp_offset
= -cfun
->machine
->save_regs_offset
;
522 else if (total_frame_size
)
524 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
,
525 gen_int_mode (-total_frame_size
,
527 RTX_FRAME_RELATED_P (insn
) = 1;
528 save_regs_base
= cfun
->machine
->save_regs_offset
;
532 save_regs_base
= sp_offset
= 0;
534 if (crtl
->limit_stack
)
535 nios2_emit_stack_limit_check ();
537 save_offset
= save_regs_base
+ cfun
->machine
->save_reg_size
;
539 for (regno
= LAST_GP_REG
; regno
> 0; regno
--)
540 if (cfun
->machine
->save_mask
& (1 << regno
))
543 save_reg (regno
, save_offset
);
546 if (frame_pointer_needed
)
548 int fp_save_offset
= save_regs_base
+ cfun
->machine
->fp_save_offset
;
549 insn
= emit_insn (gen_add3_insn (hard_frame_pointer_rtx
,
551 gen_int_mode (fp_save_offset
, Pmode
)));
552 RTX_FRAME_RELATED_P (insn
) = 1;
558 = gen_rtx_SET (stack_pointer_rtx
,
559 plus_constant (Pmode
, stack_pointer_rtx
, sp_offset
));
560 if (SMALL_INT (sp_offset
))
561 insn
= emit_insn (sp_adjust
);
564 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
565 emit_move_insn (tmp
, gen_int_mode (sp_offset
, Pmode
));
566 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
, tmp
));
567 /* Attach the sp_adjust as a note indicating what happened. */
568 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
, sp_adjust
);
570 RTX_FRAME_RELATED_P (insn
) = 1;
572 if (crtl
->limit_stack
)
573 nios2_emit_stack_limit_check ();
576 /* Load the PIC register if needed. */
577 if (crtl
->uses_pic_offset_table
)
578 nios2_load_pic_register ();
580 /* If we are profiling, make sure no instructions are scheduled before
581 the call to mcount. */
583 emit_insn (gen_blockage ());
587 nios2_expand_epilogue (bool sibcall_p
)
590 int total_frame_size
;
591 int sp_adjust
, save_offset
;
594 if (!sibcall_p
&& nios2_can_use_return_insn ())
596 emit_jump_insn (gen_return ());
600 emit_insn (gen_blockage ());
602 total_frame_size
= nios2_compute_frame_layout ();
603 if (frame_pointer_needed
)
605 /* Recover the stack pointer. */
606 insn
= emit_insn (gen_add3_insn
607 (stack_pointer_rtx
, hard_frame_pointer_rtx
,
608 gen_int_mode (-cfun
->machine
->fp_save_offset
, Pmode
)));
609 cfa_adj
= plus_constant (Pmode
, stack_pointer_rtx
,
611 - cfun
->machine
->save_regs_offset
));
612 add_reg_note (insn
, REG_CFA_DEF_CFA
, cfa_adj
);
613 RTX_FRAME_RELATED_P (insn
) = 1;
616 sp_adjust
= total_frame_size
- cfun
->machine
->save_regs_offset
;
618 else if (!SMALL_INT (total_frame_size
))
620 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
621 emit_move_insn (tmp
, gen_int_mode (cfun
->machine
->save_regs_offset
,
623 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
, tmp
));
624 cfa_adj
= gen_rtx_SET (stack_pointer_rtx
,
625 plus_constant (Pmode
, stack_pointer_rtx
,
626 cfun
->machine
->save_regs_offset
));
627 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, cfa_adj
);
628 RTX_FRAME_RELATED_P (insn
) = 1;
630 sp_adjust
= total_frame_size
- cfun
->machine
->save_regs_offset
;
634 save_offset
= cfun
->machine
->save_regs_offset
;
635 sp_adjust
= total_frame_size
;
638 save_offset
+= cfun
->machine
->save_reg_size
;
640 for (regno
= LAST_GP_REG
; regno
> 0; regno
--)
641 if (cfun
->machine
->save_mask
& (1 << regno
))
644 restore_reg (regno
, save_offset
);
649 insn
= emit_insn (gen_add2_insn (stack_pointer_rtx
,
650 gen_int_mode (sp_adjust
, Pmode
)));
651 cfa_adj
= gen_rtx_SET (stack_pointer_rtx
,
652 plus_constant (Pmode
, stack_pointer_rtx
,
654 add_reg_note (insn
, REG_CFA_ADJUST_CFA
, cfa_adj
);
655 RTX_FRAME_RELATED_P (insn
) = 1;
658 /* Add in the __builtin_eh_return stack adjustment. */
659 if (crtl
->calls_eh_return
)
660 emit_insn (gen_add2_insn (stack_pointer_rtx
, EH_RETURN_STACKADJ_RTX
));
663 emit_jump_insn (gen_simple_return ());
666 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
667 back to a previous frame. */
669 nios2_get_return_address (int count
)
674 return get_hard_reg_initial_val (Pmode
, RA_REGNO
);
677 /* Emit code to change the current function's return address to
678 ADDRESS. SCRATCH is available as a scratch register, if needed.
679 ADDRESS and SCRATCH are both word-mode GPRs. */
681 nios2_set_return_address (rtx address
, rtx scratch
)
683 nios2_compute_frame_layout ();
684 if (cfun
->machine
->save_mask
& (1 << RA_REGNO
))
686 unsigned offset
= cfun
->machine
->save_reg_size
- 4;
689 if (frame_pointer_needed
)
690 base
= hard_frame_pointer_rtx
;
693 base
= stack_pointer_rtx
;
694 offset
+= cfun
->machine
->save_regs_offset
;
696 if (!SMALL_INT (offset
))
698 emit_move_insn (scratch
, gen_int_mode (offset
, Pmode
));
699 emit_insn (gen_add2_insn (scratch
, base
));
705 base
= plus_constant (Pmode
, base
, offset
);
706 emit_move_insn (gen_rtx_MEM (Pmode
, base
), address
);
709 emit_move_insn (gen_rtx_REG (Pmode
, RA_REGNO
), address
);
712 /* Implement FUNCTION_PROFILER macro. */
714 nios2_function_profiler (FILE *file
, int labelno ATTRIBUTE_UNUSED
)
716 fprintf (file
, "\tmov\tr8, ra\n");
719 fprintf (file
, "\tnextpc\tr2\n");
720 fprintf (file
, "\t1: movhi\tr3, %%hiadj(_gp_got - 1b)\n");
721 fprintf (file
, "\taddi\tr3, r3, %%lo(_gp_got - 1b)\n");
722 fprintf (file
, "\tadd\tr2, r2, r3\n");
723 fprintf (file
, "\tldw\tr2, %%call(_mcount)(r2)\n");
724 fprintf (file
, "\tcallr\tr2\n");
726 else if (flag_pic
== 2)
728 fprintf (file
, "\tnextpc\tr2\n");
729 fprintf (file
, "\t1: movhi\tr3, %%hiadj(_gp_got - 1b)\n");
730 fprintf (file
, "\taddi\tr3, r3, %%lo(_gp_got - 1b)\n");
731 fprintf (file
, "\tadd\tr2, r2, r3\n");
732 fprintf (file
, "\tmovhi\tr3, %%call_hiadj(_mcount)\n");
733 fprintf (file
, "\taddi\tr3, r3, %%call_lo(_mcount)\n");
734 fprintf (file
, "\tadd\tr3, r2, r3\n");
735 fprintf (file
, "\tldw\tr2, 0(r3)\n");
736 fprintf (file
, "\tcallr\tr2\n");
739 fprintf (file
, "\tcall\t_mcount\n");
740 fprintf (file
, "\tmov\tra, r8\n");
743 /* Dump stack layout. */
745 nios2_dump_frame_layout (FILE *file
)
747 fprintf (file
, "\t%s Current Frame Info\n", ASM_COMMENT_START
);
748 fprintf (file
, "\t%s total_size = %d\n", ASM_COMMENT_START
,
749 cfun
->machine
->total_size
);
750 fprintf (file
, "\t%s var_size = %d\n", ASM_COMMENT_START
,
751 cfun
->machine
->var_size
);
752 fprintf (file
, "\t%s args_size = %d\n", ASM_COMMENT_START
,
753 cfun
->machine
->args_size
);
754 fprintf (file
, "\t%s save_reg_size = %d\n", ASM_COMMENT_START
,
755 cfun
->machine
->save_reg_size
);
756 fprintf (file
, "\t%s initialized = %d\n", ASM_COMMENT_START
,
757 cfun
->machine
->initialized
);
758 fprintf (file
, "\t%s save_regs_offset = %d\n", ASM_COMMENT_START
,
759 cfun
->machine
->save_regs_offset
);
760 fprintf (file
, "\t%s is_leaf = %d\n", ASM_COMMENT_START
,
762 fprintf (file
, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START
,
763 frame_pointer_needed
);
764 fprintf (file
, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START
,
765 crtl
->args
.pretend_args_size
);
768 /* Return true if REGNO should be saved in the prologue. */
770 prologue_saved_reg_p (unsigned regno
)
772 gcc_assert (GP_REG_P (regno
));
774 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
777 if (regno
== HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed
)
780 if (regno
== PIC_OFFSET_TABLE_REGNUM
&& crtl
->uses_pic_offset_table
)
783 if (regno
== RA_REGNO
&& df_regs_ever_live_p (RA_REGNO
))
789 /* Implement TARGET_CAN_ELIMINATE. */
791 nios2_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
793 if (to
== STACK_POINTER_REGNUM
)
794 return !frame_pointer_needed
;
798 /* Implement INITIAL_ELIMINATION_OFFSET macro. */
800 nios2_initial_elimination_offset (int from
, int to
)
804 nios2_compute_frame_layout ();
806 /* Set OFFSET to the offset from the stack pointer. */
809 case FRAME_POINTER_REGNUM
:
810 offset
= cfun
->machine
->args_size
;
813 case ARG_POINTER_REGNUM
:
814 offset
= cfun
->machine
->total_size
;
815 offset
-= crtl
->args
.pretend_args_size
;
822 /* If we are asked for the frame pointer offset, then adjust OFFSET
823 by the offset from the frame pointer to the stack pointer. */
824 if (to
== HARD_FRAME_POINTER_REGNUM
)
825 offset
-= (cfun
->machine
->save_regs_offset
826 + cfun
->machine
->fp_save_offset
);
831 /* Return nonzero if this function is known to have a null epilogue.
832 This allows the optimizer to omit jumps to jumps if no stack
835 nios2_can_use_return_insn (void)
837 if (!reload_completed
|| crtl
->profile
)
840 return nios2_compute_frame_layout () == 0;
844 /* Check and signal some warnings/errors on FPU insn options. */
846 nios2_custom_check_insns (void)
851 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
852 if (N2FPU_ENABLED_P (i
) && N2FPU_DOUBLE_P (i
))
854 for (j
= 0; j
< ARRAY_SIZE (nios2_fpu_insn
); j
++)
855 if (N2FPU_DOUBLE_REQUIRED_P (j
) && ! N2FPU_ENABLED_P (j
))
857 error ("switch %<-mcustom-%s%> is required for double "
858 "precision floating point", N2FPU_NAME (j
));
864 /* Warn if the user has certain exotic operations that won't get used
865 without -funsafe-math-optimizations. See expand_builtin () in
867 if (!flag_unsafe_math_optimizations
)
868 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
869 if (N2FPU_ENABLED_P (i
) && N2FPU_UNSAFE_P (i
))
870 warning (0, "switch %<-mcustom-%s%> has no effect unless "
871 "-funsafe-math-optimizations is specified", N2FPU_NAME (i
));
873 /* Warn if the user is trying to use -mcustom-fmins et. al, that won't
874 get used without -ffinite-math-only. See fold_builtin_fmin_fmax ()
876 if (!flag_finite_math_only
)
877 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
878 if (N2FPU_ENABLED_P (i
) && N2FPU_FINITE_P (i
))
879 warning (0, "switch %<-mcustom-%s%> has no effect unless "
880 "-ffinite-math-only is specified", N2FPU_NAME (i
));
882 /* Warn if the user is trying to use a custom rounding instruction
883 that won't get used without -fno-math-errno. See
884 expand_builtin_int_roundingfn_2 () in builtins.c. */
886 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
887 if (N2FPU_ENABLED_P (i
) && N2FPU_NO_ERRNO_P (i
))
888 warning (0, "switch %<-mcustom-%s%> has no effect unless "
889 "-fno-math-errno is specified", N2FPU_NAME (i
));
891 if (errors
|| custom_code_conflict
)
892 fatal_error (input_location
,
893 "conflicting use of -mcustom switches, target attributes, "
894 "and/or __builtin_custom_ functions");
898 nios2_set_fpu_custom_code (enum n2fpu_code code
, int n
, bool override_p
)
900 if (override_p
|| N2FPU_N (code
) == -1)
902 nios2_register_custom_code (n
, CCS_FPU
, (int) code
);
905 /* Type to represent a standard FPU config. */
906 struct nios2_fpu_config
909 bool set_sp_constants
;
910 int code
[n2fpu_code_num
];
913 #define NIOS2_FPU_CONFIG_NUM 3
914 static struct nios2_fpu_config custom_fpu_config
[NIOS2_FPU_CONFIG_NUM
];
917 nios2_init_fpu_configs (void)
919 struct nios2_fpu_config
* cfg
;
921 #define NEXT_FPU_CONFIG \
923 cfg = &custom_fpu_config[i++]; \
924 memset (cfg, -1, sizeof (struct nios2_fpu_config));\
929 cfg
->set_sp_constants
= true;
930 cfg
->code
[n2fpu_fmuls
] = 252;
931 cfg
->code
[n2fpu_fadds
] = 253;
932 cfg
->code
[n2fpu_fsubs
] = 254;
936 cfg
->set_sp_constants
= true;
937 cfg
->code
[n2fpu_fmuls
] = 252;
938 cfg
->code
[n2fpu_fadds
] = 253;
939 cfg
->code
[n2fpu_fsubs
] = 254;
940 cfg
->code
[n2fpu_fdivs
] = 255;
944 cfg
->set_sp_constants
= true;
945 cfg
->code
[n2fpu_floatus
] = 243;
946 cfg
->code
[n2fpu_fixsi
] = 244;
947 cfg
->code
[n2fpu_floatis
] = 245;
948 cfg
->code
[n2fpu_fcmpgts
] = 246;
949 cfg
->code
[n2fpu_fcmples
] = 249;
950 cfg
->code
[n2fpu_fcmpeqs
] = 250;
951 cfg
->code
[n2fpu_fcmpnes
] = 251;
952 cfg
->code
[n2fpu_fmuls
] = 252;
953 cfg
->code
[n2fpu_fadds
] = 253;
954 cfg
->code
[n2fpu_fsubs
] = 254;
955 cfg
->code
[n2fpu_fdivs
] = 255;
957 #undef NEXT_FPU_CONFIG
958 gcc_assert (i
== NIOS2_FPU_CONFIG_NUM
);
961 static struct nios2_fpu_config
*
962 nios2_match_custom_fpu_cfg (const char *cfgname
, const char *endp
)
965 for (i
= 0; i
< NIOS2_FPU_CONFIG_NUM
; i
++)
967 bool match
= !(endp
!= NULL
968 ? strncmp (custom_fpu_config
[i
].name
, cfgname
,
970 : strcmp (custom_fpu_config
[i
].name
, cfgname
));
972 return &custom_fpu_config
[i
];
977 /* Use CFGNAME to lookup FPU config, ENDP if not NULL marks end of string.
978 OVERRIDE is true if loaded config codes should overwrite current state. */
980 nios2_handle_custom_fpu_cfg (const char *cfgname
, const char *endp
,
983 struct nios2_fpu_config
*cfg
= nios2_match_custom_fpu_cfg (cfgname
, endp
);
987 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
988 if (cfg
->code
[i
] >= 0)
989 nios2_set_fpu_custom_code ((enum n2fpu_code
) i
, cfg
->code
[i
],
991 if (cfg
->set_sp_constants
)
992 flag_single_precision_constant
= 1;
995 warning (0, "ignoring unrecognized switch %<-mcustom-fpu-cfg%> "
996 "value %<%s%>", cfgname
);
998 /* Guard against errors in the standard configurations. */
999 nios2_custom_check_insns ();
1002 /* Check individual FPU insn options, and register custom code. */
1004 nios2_handle_custom_fpu_insn_option (int fpu_insn_index
)
1006 int param
= N2FPU_N (fpu_insn_index
);
1008 if (0 <= param
&& param
<= 255)
1009 nios2_register_custom_code (param
, CCS_FPU
, fpu_insn_index
);
1011 /* Valid values are 0-255, but also allow -1 so that the
1012 -mno-custom-<opt> switches work. */
1013 else if (param
!= -1)
1014 error ("switch %<-mcustom-%s%> value %d must be between 0 and 255",
1015 N2FPU_NAME (fpu_insn_index
), param
);
1018 /* Allocate a chunk of memory for per-function machine-dependent data. */
1019 static struct machine_function
*
1020 nios2_init_machine_status (void)
1022 return ggc_cleared_alloc
<machine_function
> ();
1025 /* Implement TARGET_OPTION_OVERRIDE. */
1027 nios2_option_override (void)
1031 #ifdef SUBTARGET_OVERRIDE_OPTIONS
1032 SUBTARGET_OVERRIDE_OPTIONS
;
1035 /* Check for unsupported options. */
1036 if (flag_pic
&& !TARGET_LINUX_ABI
)
1037 sorry ("position-independent code requires the Linux ABI");
1039 /* Function to allocate machine-dependent function status. */
1040 init_machine_status
= &nios2_init_machine_status
;
1042 nios2_section_threshold
1043 = (global_options_set
.x_g_switch_value
1044 ? g_switch_value
: NIOS2_DEFAULT_GVALUE
);
1046 if (nios2_gpopt_option
== gpopt_unspecified
)
1048 /* Default to -mgpopt unless -fpic or -fPIC. */
1050 nios2_gpopt_option
= gpopt_none
;
1052 nios2_gpopt_option
= gpopt_local
;
1055 /* If we don't have mul, we don't have mulx either! */
1056 if (!TARGET_HAS_MUL
&& TARGET_HAS_MULX
)
1057 target_flags
&= ~MASK_HAS_MULX
;
1059 /* Initialize default FPU configurations. */
1060 nios2_init_fpu_configs ();
1062 /* Set up default handling for floating point custom instructions.
1064 Putting things in this order means that the -mcustom-fpu-cfg=
1065 switch will always be overridden by individual -mcustom-fadds=
1066 switches, regardless of the order in which they were specified
1067 on the command line.
1069 This behavior of prioritization of individual -mcustom-<insn>=
1070 options before the -mcustom-fpu-cfg= switch is maintained for
1072 if (nios2_custom_fpu_cfg_string
&& *nios2_custom_fpu_cfg_string
)
1073 nios2_handle_custom_fpu_cfg (nios2_custom_fpu_cfg_string
, NULL
, false);
1075 /* Handle options for individual FPU insns. */
1076 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
1077 nios2_handle_custom_fpu_insn_option (i
);
1079 nios2_custom_check_insns ();
1081 /* Save the initial options in case the user does function specific
1083 target_option_default_node
= target_option_current_node
1084 = build_target_option_node (&global_options
);
1088 /* Return true if CST is a constant within range of movi/movui/movhi. */
1090 nios2_simple_const_p (const_rtx cst
)
1092 HOST_WIDE_INT val
= INTVAL (cst
);
1093 return SMALL_INT (val
) || SMALL_INT_UNSIGNED (val
) || UPPER16_INT (val
);
1096 /* Compute a (partial) cost for rtx X. Return true if the complete
1097 cost has been computed, and false if subexpressions should be
1098 scanned. In either case, *TOTAL contains the cost result. */
1100 nios2_rtx_costs (rtx x
, int code
, int outer_code ATTRIBUTE_UNUSED
,
1101 int opno ATTRIBUTE_UNUSED
,
1102 int *total
, bool speed ATTRIBUTE_UNUSED
)
1107 if (INTVAL (x
) == 0)
1109 *total
= COSTS_N_INSNS (0);
1112 else if (nios2_simple_const_p (x
))
1114 *total
= COSTS_N_INSNS (2);
1119 *total
= COSTS_N_INSNS (4);
1128 *total
= COSTS_N_INSNS (4);
1134 /* Recognize 'nor' insn pattern. */
1135 if (GET_CODE (XEXP (x
, 0)) == NOT
1136 && GET_CODE (XEXP (x
, 1)) == NOT
)
1138 *total
= COSTS_N_INSNS (1);
1146 *total
= COSTS_N_INSNS (1);
1151 *total
= COSTS_N_INSNS (3);
1156 *total
= COSTS_N_INSNS (1);
1165 /* Implement TARGET_PREFERRED_RELOAD_CLASS. */
1167 nios2_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, reg_class_t regclass
)
1169 return regclass
== NO_REGS
? GENERAL_REGS
: regclass
;
1172 /* Emit a call to __tls_get_addr. TI is the argument to this function.
1173 RET is an RTX for the return value location. The entire insn sequence
1175 static GTY(()) rtx nios2_tls_symbol
;
1178 nios2_call_tls_get_addr (rtx ti
)
1180 rtx arg
= gen_rtx_REG (Pmode
, FIRST_ARG_REGNO
);
1181 rtx ret
= gen_rtx_REG (Pmode
, FIRST_RETVAL_REGNO
);
1184 if (!nios2_tls_symbol
)
1185 nios2_tls_symbol
= init_one_libfunc ("__tls_get_addr");
1187 emit_move_insn (arg
, ti
);
1188 fn
= gen_rtx_MEM (QImode
, nios2_tls_symbol
);
1189 insn
= emit_call_insn (gen_call_value (ret
, fn
, const0_rtx
));
1190 RTL_CONST_CALL_P (insn
) = 1;
1191 use_reg (&CALL_INSN_FUNCTION_USAGE (insn
), ret
);
1192 use_reg (&CALL_INSN_FUNCTION_USAGE (insn
), arg
);
1197 /* Return true for large offsets requiring hiadj/lo relocation pairs. */
1199 nios2_large_offset_p (int unspec
)
1201 gcc_assert (nios2_unspec_reloc_name (unspec
) != NULL
);
1204 /* FIXME: TLS GOT offset relocations will eventually also get this
1205 treatment, after binutils support for those are also completed. */
1206 && (unspec
== UNSPEC_PIC_SYM
|| unspec
== UNSPEC_PIC_CALL_SYM
))
1209 /* 'gotoff' offsets are always hiadj/lo. */
1210 if (unspec
== UNSPEC_PIC_GOTOFF_SYM
)
1216 /* Return true for conforming unspec relocations. Also used in
1217 constraints.md and predicates.md. */
1219 nios2_unspec_reloc_p (rtx op
)
1221 return (GET_CODE (op
) == CONST
1222 && GET_CODE (XEXP (op
, 0)) == UNSPEC
1223 && ! nios2_large_offset_p (XINT (XEXP (op
, 0), 1)));
1226 /* Helper to generate unspec constant. */
1228 nios2_unspec_offset (rtx loc
, int unspec
)
1230 return gen_rtx_CONST (Pmode
, gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, loc
),
1234 /* Generate GOT pointer based address with large offset. */
1236 nios2_large_got_address (rtx offset
, rtx tmp
)
1239 tmp
= gen_reg_rtx (Pmode
);
1240 emit_move_insn (tmp
, offset
);
1241 return gen_rtx_PLUS (Pmode
, tmp
, pic_offset_table_rtx
);
1244 /* Generate a GOT pointer based address. */
1246 nios2_got_address (rtx loc
, int unspec
)
1248 rtx offset
= nios2_unspec_offset (loc
, unspec
);
1249 crtl
->uses_pic_offset_table
= 1;
1251 if (nios2_large_offset_p (unspec
))
1252 return force_reg (Pmode
, nios2_large_got_address (offset
, NULL_RTX
));
1254 return gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, offset
);
1257 /* Generate the code to access LOC, a thread local SYMBOL_REF. The
1258 return value will be a valid address and move_operand (either a REG
1261 nios2_legitimize_tls_address (rtx loc
)
1264 enum tls_model model
= SYMBOL_REF_TLS_MODEL (loc
);
1268 case TLS_MODEL_GLOBAL_DYNAMIC
:
1269 tmp
= gen_reg_rtx (Pmode
);
1270 emit_move_insn (tmp
, nios2_got_address (loc
, UNSPEC_ADD_TLS_GD
));
1271 return nios2_call_tls_get_addr (tmp
);
1273 case TLS_MODEL_LOCAL_DYNAMIC
:
1274 tmp
= gen_reg_rtx (Pmode
);
1275 emit_move_insn (tmp
, nios2_got_address (loc
, UNSPEC_ADD_TLS_LDM
));
1276 return gen_rtx_PLUS (Pmode
, nios2_call_tls_get_addr (tmp
),
1277 nios2_unspec_offset (loc
, UNSPEC_ADD_TLS_LDO
));
1279 case TLS_MODEL_INITIAL_EXEC
:
1280 tmp
= gen_reg_rtx (Pmode
);
1281 mem
= gen_const_mem (Pmode
, nios2_got_address (loc
, UNSPEC_LOAD_TLS_IE
));
1282 emit_move_insn (tmp
, mem
);
1283 tp
= gen_rtx_REG (Pmode
, TP_REGNO
);
1284 return gen_rtx_PLUS (Pmode
, tp
, tmp
);
1286 case TLS_MODEL_LOCAL_EXEC
:
1287 tp
= gen_rtx_REG (Pmode
, TP_REGNO
);
1288 return gen_rtx_PLUS (Pmode
, tp
,
1289 nios2_unspec_offset (loc
, UNSPEC_ADD_TLS_LE
));
1297 If -O3 is used, we want to output a table lookup for
1298 divides between small numbers (both num and den >= 0
1299 and < 0x10). The overhead of this method in the worst
1300 case is 40 bytes in the text section (10 insns) and
1301 256 bytes in the data section. Additional divides do
1302 not incur additional penalties in the data section.
1304 Code speed is improved for small divides by about 5x
1305 when using this method in the worse case (~9 cycles
1306 vs ~45). And in the worst case divides not within the
1307 table are penalized by about 10% (~5 cycles vs ~45).
1308 However in the typical case the penalty is not as bad
1309 because doing the long divide in only 45 cycles is
1312 ??? would be nice to have some benchmarks other
1313 than Dhrystone to back this up.
1315 This bit of expansion is to create this instruction
1322 add $12, $11, divide_table
1328 # continue here with result in $2
1330 ??? Ideally I would like the libcall block to contain all
1331 of this code, but I don't know how to do that. What it
1332 means is that if the divide can be eliminated, it may not
1333 completely disappear.
1335 ??? The __divsi3_table label should ideally be moved out
1336 of this block and into a global. If it is placed into the
1337 sdata section we can save even more cycles by doing things
1340 nios2_emit_expensive_div (rtx
*operands
, machine_mode mode
)
1342 rtx or_result
, shift_left_result
;
1344 rtx_code_label
*lab1
, *lab3
;
1351 /* It may look a little generic, but only SImode is supported for now. */
1352 gcc_assert (mode
== SImode
);
1353 libfunc
= optab_libfunc (sdiv_optab
, SImode
);
1355 lab1
= gen_label_rtx ();
1356 lab3
= gen_label_rtx ();
1358 or_result
= expand_simple_binop (SImode
, IOR
,
1359 operands
[1], operands
[2],
1360 0, 0, OPTAB_LIB_WIDEN
);
1362 emit_cmp_and_jump_insns (or_result
, GEN_INT (15), GTU
, 0,
1363 GET_MODE (or_result
), 0, lab3
);
1364 JUMP_LABEL (get_last_insn ()) = lab3
;
1366 shift_left_result
= expand_simple_binop (SImode
, ASHIFT
,
1367 operands
[1], GEN_INT (4),
1368 0, 0, OPTAB_LIB_WIDEN
);
1370 lookup_value
= expand_simple_binop (SImode
, IOR
,
1371 shift_left_result
, operands
[2],
1372 0, 0, OPTAB_LIB_WIDEN
);
1373 table
= gen_rtx_PLUS (SImode
, lookup_value
,
1374 gen_rtx_SYMBOL_REF (SImode
, "__divsi3_table"));
1375 convert_move (operands
[0], gen_rtx_MEM (QImode
, table
), 1);
1377 tmp
= emit_jump_insn (gen_jump (lab1
));
1378 JUMP_LABEL (tmp
) = lab1
;
1382 LABEL_NUSES (lab3
) = 1;
1385 final_result
= emit_library_call_value (libfunc
, NULL_RTX
,
1386 LCT_CONST
, SImode
, 2,
1387 operands
[1], SImode
,
1388 operands
[2], SImode
);
1390 insns
= get_insns ();
1392 emit_libcall_block (insns
, operands
[0], final_result
,
1393 gen_rtx_DIV (SImode
, operands
[1], operands
[2]));
1396 LABEL_NUSES (lab1
) = 1;
1400 /* Branches and compares. */
1402 /* Return in *ALT_CODE and *ALT_OP, an alternate equivalent constant
1403 comparison, e.g. >= 1 into > 0. */
1405 nios2_alternate_compare_const (enum rtx_code code
, rtx op
,
1406 enum rtx_code
*alt_code
, rtx
*alt_op
,
1409 HOST_WIDE_INT opval
= INTVAL (op
);
1410 enum rtx_code scode
= signed_condition (code
);
1411 bool dec_p
= (scode
== LT
|| scode
== GE
);
1413 if (code
== EQ
|| code
== NE
)
1421 ? gen_int_mode (opval
- 1, mode
)
1422 : gen_int_mode (opval
+ 1, mode
));
1424 /* The required conversion between [>,>=] and [<,<=] is captured
1425 by a reverse + swap of condition codes. */
1426 *alt_code
= reverse_condition (swap_condition (code
));
1429 /* Test if the incremented/decremented value crosses the over/underflow
1430 boundary. Supposedly, such boundary cases should already be transformed
1431 into always-true/false or EQ conditions, so use an assertion here. */
1432 unsigned HOST_WIDE_INT alt_opval
= INTVAL (*alt_op
);
1434 alt_opval
^= (1 << (GET_MODE_BITSIZE (mode
) - 1));
1435 alt_opval
&= GET_MODE_MASK (mode
);
1436 gcc_assert (dec_p
? alt_opval
!= GET_MODE_MASK (mode
) : alt_opval
!= 0);
1440 /* Return true if the constant comparison is supported by nios2. */
1442 nios2_valid_compare_const_p (enum rtx_code code
, rtx op
)
1446 case EQ
: case NE
: case GE
: case LT
:
1447 return SMALL_INT (INTVAL (op
));
1449 return SMALL_INT_UNSIGNED (INTVAL (op
));
1455 /* Checks if the FPU comparison in *CMP, *OP1, and *OP2 can be supported in
1456 the current configuration. Perform modifications if MODIFY_P is true.
1457 Returns true if FPU compare can be done. */
1460 nios2_validate_fpu_compare (machine_mode mode
, rtx
*cmp
, rtx
*op1
, rtx
*op2
,
1464 enum rtx_code code
= GET_CODE (*cmp
);
1466 if (!nios2_fpu_compare_enabled (code
, mode
))
1468 code
= swap_condition (code
);
1469 if (nios2_fpu_compare_enabled (code
, mode
))
1483 *op1
= force_reg (mode
, *op1
);
1484 *op2
= force_reg (mode
, *op2
);
1485 *cmp
= gen_rtx_fmt_ee (code
, mode
, *op1
, *op2
);
1490 /* Checks and modifies the comparison in *CMP, *OP1, and *OP2 into valid
1491 nios2 supported form. Returns true if success. */
1493 nios2_validate_compare (machine_mode mode
, rtx
*cmp
, rtx
*op1
, rtx
*op2
)
1495 enum rtx_code code
= GET_CODE (*cmp
);
1496 enum rtx_code alt_code
;
1499 if (GET_MODE_CLASS (mode
) == MODE_FLOAT
)
1500 return nios2_validate_fpu_compare (mode
, cmp
, op1
, op2
, true);
1502 if (!reg_or_0_operand (*op2
, mode
))
1504 /* Create alternate constant compare. */
1505 nios2_alternate_compare_const (code
, *op2
, &alt_code
, &alt_op2
, mode
);
1507 /* If alterate op2 is zero(0), we can use it directly, possibly
1508 swapping the compare code. */
1509 if (alt_op2
== const0_rtx
)
1513 goto check_rebuild_cmp
;
1516 /* Check if either constant compare can be used. */
1517 if (nios2_valid_compare_const_p (code
, *op2
))
1519 else if (nios2_valid_compare_const_p (alt_code
, alt_op2
))
1526 /* We have to force op2 into a register now. Try to pick one
1527 with a lower cost. */
1528 if (! nios2_simple_const_p (*op2
)
1529 && nios2_simple_const_p (alt_op2
))
1534 *op2
= force_reg (SImode
, *op2
);
1537 if (code
== GT
|| code
== GTU
|| code
== LE
|| code
== LEU
)
1539 rtx t
= *op1
; *op1
= *op2
; *op2
= t
;
1540 code
= swap_condition (code
);
1543 *cmp
= gen_rtx_fmt_ee (code
, mode
, *op1
, *op2
);
1548 /* Addressing Modes. */
1550 /* Implement TARGET_LEGITIMATE_CONSTANT_P. */
1552 nios2_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
1555 split_const (x
, &base
, &offset
);
1556 return GET_CODE (base
) != SYMBOL_REF
|| !SYMBOL_REF_TLS_MODEL (base
);
1559 /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
1561 nios2_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
1563 return nios2_legitimate_constant_p (mode
, x
) == false;
1566 /* Return true if register REGNO is a valid base register.
1567 STRICT_P is true if REG_OK_STRICT is in effect. */
1570 nios2_regno_ok_for_base_p (int regno
, bool strict_p
)
1572 if (!HARD_REGISTER_NUM_P (regno
))
1580 regno
= reg_renumber
[regno
];
1583 /* The fake registers will be eliminated to either the stack or
1584 hard frame pointer, both of which are usually valid base registers.
1585 Reload deals with the cases where the eliminated form isn't valid. */
1586 return (GP_REG_P (regno
)
1587 || regno
== FRAME_POINTER_REGNUM
1588 || regno
== ARG_POINTER_REGNUM
);
1591 /* Return true if the address expression formed by BASE + OFFSET is
1594 nios2_valid_addr_expr_p (rtx base
, rtx offset
, bool strict_p
)
1596 if (!strict_p
&& GET_CODE (base
) == SUBREG
)
1597 base
= SUBREG_REG (base
);
1598 return (REG_P (base
)
1599 && nios2_regno_ok_for_base_p (REGNO (base
), strict_p
)
1600 && (offset
== NULL_RTX
1601 || const_arith_operand (offset
, Pmode
)
1602 || nios2_unspec_reloc_p (offset
)));
1605 /* Implement TARGET_LEGITIMATE_ADDRESS_P. */
1607 nios2_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED
,
1608 rtx operand
, bool strict_p
)
1610 switch (GET_CODE (operand
))
1614 if (SYMBOL_REF_TLS_MODEL (operand
))
1617 if (nios2_symbol_ref_in_small_data_p (operand
))
1620 /* Else, fall through. */
1627 /* Register indirect. */
1629 return nios2_regno_ok_for_base_p (REGNO (operand
), strict_p
);
1631 /* Register indirect with displacement. */
1634 rtx op0
= XEXP (operand
, 0);
1635 rtx op1
= XEXP (operand
, 1);
1637 return (nios2_valid_addr_expr_p (op0
, op1
, strict_p
)
1638 || nios2_valid_addr_expr_p (op1
, op0
, strict_p
));
1647 /* Return true if SECTION is a small section name. */
1649 nios2_small_section_name_p (const char *section
)
1651 return (strcmp (section
, ".sbss") == 0
1652 || strncmp (section
, ".sbss.", 6) == 0
1653 || strcmp (section
, ".sdata") == 0
1654 || strncmp (section
, ".sdata.", 7) == 0);
1657 /* Return true if EXP should be placed in the small data section. */
1659 nios2_in_small_data_p (const_tree exp
)
1661 /* We want to merge strings, so we never consider them small data. */
1662 if (TREE_CODE (exp
) == STRING_CST
)
1665 if (TREE_CODE (exp
) == VAR_DECL
)
1667 if (DECL_SECTION_NAME (exp
))
1669 const char *section
= DECL_SECTION_NAME (exp
);
1670 if (nios2_small_section_name_p (section
))
1675 HOST_WIDE_INT size
= int_size_in_bytes (TREE_TYPE (exp
));
1677 /* If this is an incomplete type with size 0, then we can't put it
1678 in sdata because it might be too big when completed. */
1680 && (unsigned HOST_WIDE_INT
) size
<= nios2_section_threshold
)
1688 /* Return true if symbol is in small data section. */
1691 nios2_symbol_ref_in_small_data_p (rtx sym
)
1695 gcc_assert (GET_CODE (sym
) == SYMBOL_REF
);
1696 decl
= SYMBOL_REF_DECL (sym
);
1698 /* TLS variables are not accessed through the GP. */
1699 if (SYMBOL_REF_TLS_MODEL (sym
) != 0)
1702 /* If the user has explicitly placed the symbol in a small data section
1703 via an attribute, generate gp-relative addressing even if the symbol
1704 is external, weak, or larger than we'd automatically put in the
1705 small data section. OTOH, if the symbol is located in some
1706 non-small-data section, we can't use gp-relative accesses on it
1707 unless the user has requested gpopt_data or gpopt_all. */
1709 switch (nios2_gpopt_option
)
1712 /* Don't generate a gp-relative addressing mode if that's been
1717 /* Use GP-relative addressing for small data symbols that are
1718 not external or weak, plus any symbols that have explicitly
1719 been placed in a small data section. */
1720 if (decl
&& DECL_SECTION_NAME (decl
))
1721 return nios2_small_section_name_p (DECL_SECTION_NAME (decl
));
1722 return (SYMBOL_REF_SMALL_P (sym
)
1723 && !SYMBOL_REF_EXTERNAL_P (sym
)
1724 && !(decl
&& DECL_WEAK (decl
)));
1727 /* Use GP-relative addressing for small data symbols, even if
1728 they are external or weak. Note that SYMBOL_REF_SMALL_P
1729 is also true of symbols that have explicitly been placed
1730 in a small data section. */
1731 return SYMBOL_REF_SMALL_P (sym
);
1734 /* Use GP-relative addressing for all data symbols regardless
1735 of the object size, but not for code symbols. This option
1736 is equivalent to the user asserting that the entire data
1737 section is accessible from the GP. */
1738 return !SYMBOL_REF_FUNCTION_P (sym
);
1741 /* Use GP-relative addressing for everything, including code.
1742 Effectively, the user has asserted that the entire program
1743 fits within the 64K range of the GP offset. */
1747 /* We shouldn't get here. */
1752 /* Implement TARGET_SECTION_TYPE_FLAGS. */
1755 nios2_section_type_flags (tree decl
, const char *name
, int reloc
)
1759 flags
= default_section_type_flags (decl
, name
, reloc
);
1761 if (nios2_small_section_name_p (name
))
1762 flags
|= SECTION_SMALL
;
1767 /* Return true if SYMBOL_REF X binds locally. */
1770 nios2_symbol_binds_local_p (const_rtx x
)
1772 return (SYMBOL_REF_DECL (x
)
1773 ? targetm
.binds_local_p (SYMBOL_REF_DECL (x
))
1774 : SYMBOL_REF_LOCAL_P (x
));
1777 /* Position independent code related. */
1779 /* Emit code to load the PIC register. */
1781 nios2_load_pic_register (void)
1783 rtx tmp
= gen_rtx_REG (Pmode
, TEMP_REG_NUM
);
1785 emit_insn (gen_load_got_register (pic_offset_table_rtx
, tmp
));
1786 emit_insn (gen_add3_insn (pic_offset_table_rtx
, pic_offset_table_rtx
, tmp
));
1789 /* Generate a PIC address as a MEM rtx. */
1791 nios2_load_pic_address (rtx sym
, int unspec
, rtx tmp
)
1794 && GET_CODE (sym
) == SYMBOL_REF
1795 && nios2_symbol_binds_local_p (sym
))
1796 /* Under -fPIC, generate a GOTOFF address for local symbols. */
1798 rtx offset
= nios2_unspec_offset (sym
, UNSPEC_PIC_GOTOFF_SYM
);
1799 crtl
->uses_pic_offset_table
= 1;
1800 return nios2_large_got_address (offset
, tmp
);
1803 return gen_const_mem (Pmode
, nios2_got_address (sym
, unspec
));
1806 /* Nonzero if the constant value X is a legitimate general operand
1807 when generating PIC code. It is given that flag_pic is on and
1808 that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
1810 nios2_legitimate_pic_operand_p (rtx x
)
1812 if (GET_CODE (x
) == CONST
1813 && GET_CODE (XEXP (x
, 0)) == UNSPEC
1814 && nios2_large_offset_p (XINT (XEXP (x
, 0), 1)))
1817 return ! (GET_CODE (x
) == SYMBOL_REF
1818 || GET_CODE (x
) == LABEL_REF
|| GET_CODE (x
) == CONST
);
1821 /* Return TRUE if X is a thread-local symbol. */
1823 nios2_tls_symbol_p (rtx x
)
1825 return (targetm
.have_tls
&& GET_CODE (x
) == SYMBOL_REF
1826 && SYMBOL_REF_TLS_MODEL (x
) != 0);
1829 /* Legitimize addresses that are CONSTANT_P expressions. */
1831 nios2_legitimize_constant_address (rtx addr
)
1834 split_const (addr
, &base
, &offset
);
1836 if (nios2_tls_symbol_p (base
))
1837 base
= nios2_legitimize_tls_address (base
);
1839 base
= nios2_load_pic_address (base
, UNSPEC_PIC_SYM
, NULL_RTX
);
1843 if (offset
!= const0_rtx
)
1845 gcc_assert (can_create_pseudo_p ());
1846 return gen_rtx_PLUS (Pmode
, force_reg (Pmode
, base
),
1847 (CONST_INT_P (offset
)
1848 ? (SMALL_INT (INTVAL (offset
))
1849 ? offset
: force_reg (Pmode
, offset
))
1855 /* Implement TARGET_LEGITIMIZE_ADDRESS. */
1857 nios2_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
1858 machine_mode mode ATTRIBUTE_UNUSED
)
1861 return nios2_legitimize_constant_address (x
);
1863 /* For the TLS LE (Local Exec) model, the compiler may try to
1864 combine constant offsets with unspec relocs, creating address RTXs
1866 (plus:SI (reg:SI 23 r23)
1869 (unspec:SI [(symbol_ref:SI ("var"))] UNSPEC_ADD_TLS_LE)
1870 (const_int 48 [0x30]))))
1872 This usually happens when 'var' is a thread-local struct variable,
1873 and access of a field in var causes the addend.
1875 We typically want this combining, so transform the above into this
1876 form, which is allowed:
1877 (plus:SI (reg:SI 23 r23)
1881 (plus:SI (symbol_ref:SI ("var"))
1882 (const_int 48 [0x30])))] UNSPEC_ADD_TLS_LE)))
1884 Which will be output as '%tls_le(var+48)(r23)' in assembly. */
1885 if (GET_CODE (x
) == PLUS
1886 && GET_CODE (XEXP (x
, 0)) == REG
1887 && GET_CODE (XEXP (x
, 1)) == CONST
)
1889 rtx unspec
, offset
, reg
= XEXP (x
, 0);
1890 split_const (XEXP (x
, 1), &unspec
, &offset
);
1891 if (GET_CODE (unspec
) == UNSPEC
1892 && !nios2_large_offset_p (XINT (unspec
, 1))
1893 && offset
!= const0_rtx
)
1895 unspec
= copy_rtx (unspec
);
1896 XVECEXP (unspec
, 0, 0)
1897 = plus_constant (Pmode
, XVECEXP (unspec
, 0, 0), INTVAL (offset
));
1898 x
= gen_rtx_PLUS (Pmode
, reg
, gen_rtx_CONST (Pmode
, unspec
));
1906 nios2_delegitimize_address (rtx x
)
1908 x
= delegitimize_mem_from_attrs (x
);
1910 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == UNSPEC
)
1912 switch (XINT (XEXP (x
, 0), 1))
1914 case UNSPEC_PIC_SYM
:
1915 case UNSPEC_PIC_CALL_SYM
:
1916 case UNSPEC_PIC_GOTOFF_SYM
:
1917 case UNSPEC_ADD_TLS_GD
:
1918 case UNSPEC_ADD_TLS_LDM
:
1919 case UNSPEC_LOAD_TLS_IE
:
1920 case UNSPEC_ADD_TLS_LE
:
1921 x
= XVECEXP (XEXP (x
, 0), 0, 0);
1922 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
1929 /* Main expander function for RTL moves. */
1931 nios2_emit_move_sequence (rtx
*operands
, machine_mode mode
)
1933 rtx to
= operands
[0];
1934 rtx from
= operands
[1];
1936 if (!register_operand (to
, mode
) && !reg_or_0_operand (from
, mode
))
1938 gcc_assert (can_create_pseudo_p ());
1939 from
= copy_to_mode_reg (mode
, from
);
1942 if (GET_CODE (from
) == SYMBOL_REF
|| GET_CODE (from
) == LABEL_REF
1943 || (GET_CODE (from
) == CONST
1944 && GET_CODE (XEXP (from
, 0)) != UNSPEC
))
1945 from
= nios2_legitimize_constant_address (from
);
1952 /* The function with address *ADDR is being called. If the address
1953 needs to be loaded from the GOT, emit the instruction to do so and
1954 update *ADDR to point to the rtx for the loaded value.
1955 If REG != NULL_RTX, it is used as the target/scratch register in the
1956 GOT address calculation. */
1958 nios2_adjust_call_address (rtx
*call_op
, rtx reg
)
1960 if (MEM_P (*call_op
))
1961 call_op
= &XEXP (*call_op
, 0);
1963 rtx addr
= *call_op
;
1964 if (flag_pic
&& CONSTANT_P (addr
))
1966 rtx tmp
= reg
? reg
: NULL_RTX
;
1968 reg
= gen_reg_rtx (Pmode
);
1969 addr
= nios2_load_pic_address (addr
, UNSPEC_PIC_CALL_SYM
, tmp
);
1970 emit_insn (gen_rtx_SET (reg
, addr
));
1976 /* Output assembly language related definitions. */
1978 /* Print the operand OP to file stream FILE modified by LETTER.
1979 LETTER can be one of:
1981 i: print "i" if OP is an immediate, except 0
1982 o: print "io" if OP is volatile
1983 z: for const0_rtx print $0 instead of 0
1986 U: for upper half of 32 bit value
1987 D: for the upper 32-bits of a 64-bit double value
1988 R: prints reverse condition.
1991 nios2_print_operand (FILE *file
, rtx op
, int letter
)
1997 if (CONSTANT_P (op
) && op
!= const0_rtx
)
1998 fprintf (file
, "i");
2002 if (GET_CODE (op
) == MEM
2003 && ((MEM_VOLATILE_P (op
) && TARGET_BYPASS_CACHE_VOLATILE
)
2004 || TARGET_BYPASS_CACHE
))
2005 fprintf (file
, "io");
2012 if (comparison_operator (op
, VOIDmode
))
2014 enum rtx_code cond
= GET_CODE (op
);
2017 fprintf (file
, "%s", GET_RTX_NAME (cond
));
2022 fprintf (file
, "%s", GET_RTX_NAME (reverse_condition (cond
)));
2027 switch (GET_CODE (op
))
2030 if (letter
== 0 || letter
== 'z')
2032 fprintf (file
, "%s", reg_names
[REGNO (op
)]);
2035 else if (letter
== 'D')
2037 fprintf (file
, "%s", reg_names
[REGNO (op
)+1]);
2043 if (INTVAL (op
) == 0 && letter
== 'z')
2045 fprintf (file
, "zero");
2051 HOST_WIDE_INT val
= INTVAL (op
);
2052 val
= (val
>> 16) & 0xFFFF;
2053 output_addr_const (file
, gen_int_mode (val
, SImode
));
2056 /* Else, fall through. */
2062 if (letter
== 0 || letter
== 'z')
2064 output_addr_const (file
, op
);
2067 else if (letter
== 'H' || letter
== 'L')
2069 fprintf (file
, "%%");
2070 if (GET_CODE (op
) == CONST
2071 && GET_CODE (XEXP (op
, 0)) == UNSPEC
)
2073 rtx unspec
= XEXP (op
, 0);
2074 int unspec_reloc
= XINT (unspec
, 1);
2075 gcc_assert (nios2_large_offset_p (unspec_reloc
));
2076 fprintf (file
, "%s_", nios2_unspec_reloc_name (unspec_reloc
));
2077 op
= XVECEXP (unspec
, 0, 0);
2079 fprintf (file
, letter
== 'H' ? "hiadj(" : "lo(");
2080 output_addr_const (file
, op
);
2081 fprintf (file
, ")");
2090 output_address (op
);
2098 output_addr_const (file
, op
);
2107 output_operand_lossage ("Unsupported operand for code '%c'", letter
);
2111 /* Return true if this is a GP-relative accessible reference. */
2113 gprel_constant_p (rtx op
)
2115 if (GET_CODE (op
) == SYMBOL_REF
2116 && nios2_symbol_ref_in_small_data_p (op
))
2118 else if (GET_CODE (op
) == CONST
2119 && GET_CODE (XEXP (op
, 0)) == PLUS
)
2120 return gprel_constant_p (XEXP (XEXP (op
, 0), 0));
2125 /* Return the name string for a supported unspec reloc offset. */
2127 nios2_unspec_reloc_name (int unspec
)
2131 case UNSPEC_PIC_SYM
:
2133 case UNSPEC_PIC_CALL_SYM
:
2135 case UNSPEC_PIC_GOTOFF_SYM
:
2137 case UNSPEC_LOAD_TLS_IE
:
2139 case UNSPEC_ADD_TLS_LE
:
2141 case UNSPEC_ADD_TLS_GD
:
2143 case UNSPEC_ADD_TLS_LDM
:
2145 case UNSPEC_ADD_TLS_LDO
:
2152 /* Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA. */
2154 nios2_output_addr_const_extra (FILE *file
, rtx op
)
2157 gcc_assert (GET_CODE (op
) == UNSPEC
);
2159 /* Support for printing out const unspec relocations. */
2160 name
= nios2_unspec_reloc_name (XINT (op
, 1));
2163 fprintf (file
, "%%%s(", name
);
2164 output_addr_const (file
, XVECEXP (op
, 0, 0));
2165 fprintf (file
, ")");
2171 /* Implement TARGET_PRINT_OPERAND_ADDRESS. */
2173 nios2_print_operand_address (FILE *file
, rtx op
)
2175 switch (GET_CODE (op
))
2182 if (gprel_constant_p (op
))
2184 fprintf (file
, "%%gprel(");
2185 output_addr_const (file
, op
);
2186 fprintf (file
, ")(%s)", reg_names
[GP_REGNO
]);
2194 rtx op0
= XEXP (op
, 0);
2195 rtx op1
= XEXP (op
, 1);
2197 if (REG_P (op0
) && CONSTANT_P (op1
))
2199 output_addr_const (file
, op1
);
2200 fprintf (file
, "(%s)", reg_names
[REGNO (op0
)]);
2203 else if (REG_P (op1
) && CONSTANT_P (op0
))
2205 output_addr_const (file
, op0
);
2206 fprintf (file
, "(%s)", reg_names
[REGNO (op1
)]);
2213 fprintf (file
, "0(%s)", reg_names
[REGNO (op
)]);
2218 rtx base
= XEXP (op
, 0);
2219 nios2_print_operand_address (file
, base
);
2226 fprintf (stderr
, "Missing way to print address\n");
2231 /* Implement TARGET_ASM_OUTPUT_DWARF_DTPREL. */
2233 nios2_output_dwarf_dtprel (FILE *file
, int size
, rtx x
)
2235 gcc_assert (size
== 4);
2236 fprintf (file
, "\t.4byte\t%%tls_ldo(");
2237 output_addr_const (file
, x
);
2238 fprintf (file
, ")");
2241 /* Implemet TARGET_ASM_FILE_END. */
2244 nios2_asm_file_end (void)
2246 /* The Nios II Linux stack is mapped non-executable by default, so add a
2247 .note.GNU-stack section for switching to executable stacks only when
2248 trampolines are generated. */
2249 if (TARGET_LINUX_ABI
&& trampolines_created
)
2250 file_end_indicate_exec_stack ();
2253 /* Implement TARGET_ASM_FUNCTION_PROLOGUE. */
2255 nios2_asm_function_prologue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2257 if (flag_verbose_asm
|| flag_debug_asm
)
2259 nios2_compute_frame_layout ();
2260 nios2_dump_frame_layout (file
);
2264 /* Emit assembly of custom FPU instructions. */
2266 nios2_fpu_insn_asm (enum n2fpu_code code
)
2268 static char buf
[256];
2269 const char *op1
, *op2
, *op3
;
2270 int ln
= 256, n
= 0;
2272 int N
= N2FPU_N (code
);
2273 int num_operands
= N2FPU (code
).num_operands
;
2274 const char *insn_name
= N2FPU_NAME (code
);
2275 tree ftype
= nios2_ftype (N2FPU_FTCODE (code
));
2276 machine_mode dst_mode
= TYPE_MODE (TREE_TYPE (ftype
));
2277 machine_mode src_mode
= TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (ftype
)));
2279 /* Prepare X register for DF input operands. */
2280 if (GET_MODE_SIZE (src_mode
) == 8 && num_operands
== 3)
2281 n
= snprintf (buf
, ln
, "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t",
2282 N2FPU_N (n2fpu_fwrx
));
2284 if (src_mode
== SFmode
)
2286 if (dst_mode
== VOIDmode
)
2288 /* The fwry case. */
2295 op1
= (dst_mode
== DFmode
? "%D0" : "%0");
2297 op3
= (num_operands
== 2 ? "zero" : "%2");
2300 else if (src_mode
== DFmode
)
2302 if (dst_mode
== VOIDmode
)
2304 /* The fwrx case. */
2312 op1
= (dst_mode
== DFmode
? "%D0" : "%0");
2313 op2
= (num_operands
== 2 ? "%1" : "%2");
2314 op3
= (num_operands
== 2 ? "%D1" : "%D2");
2317 else if (src_mode
== VOIDmode
)
2319 /* frdxlo, frdxhi, frdy cases. */
2320 gcc_assert (dst_mode
== SFmode
);
2324 else if (src_mode
== SImode
)
2326 /* Conversion operators. */
2327 gcc_assert (num_operands
== 2);
2328 op1
= (dst_mode
== DFmode
? "%D0" : "%0");
2335 /* Main instruction string. */
2336 n
+= snprintf (buf
+ n
, ln
- n
, "custom\t%d, %s, %s, %s # %s %%0%s%s",
2337 N
, op1
, op2
, op3
, insn_name
,
2338 (num_operands
>= 2 ? ", %1" : ""),
2339 (num_operands
== 3 ? ", %2" : ""));
2341 /* Extraction of Y register for DF results. */
2342 if (dst_mode
== DFmode
)
2343 snprintf (buf
+ n
, ln
- n
, "\n\tcustom\t%d, %%0, zero, zero # frdy %%0",
2344 N2FPU_N (n2fpu_frdy
));
2350 /* Function argument related. */
2352 /* Define where to put the arguments to a function. Value is zero to
2353 push the argument on the stack, or a hard register in which to
2356 MODE is the argument's machine mode.
2357 TYPE is the data type of the argument (as a tree).
2358 This is null for libcalls where that information may
2360 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2361 the preceding args and about the function being called.
2362 NAMED is nonzero if this argument is a named parameter
2363 (otherwise it is an extra parameter matching an ellipsis). */
2366 nios2_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
2367 const_tree type ATTRIBUTE_UNUSED
,
2368 bool named ATTRIBUTE_UNUSED
)
2370 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2371 rtx return_rtx
= NULL_RTX
;
2373 if (cum
->regs_used
< NUM_ARG_REGS
)
2374 return_rtx
= gen_rtx_REG (mode
, FIRST_ARG_REGNO
+ cum
->regs_used
);
2379 /* Return number of bytes, at the beginning of the argument, that must be
2380 put in registers. 0 is the argument is entirely in registers or entirely
2384 nios2_arg_partial_bytes (cumulative_args_t cum_v
,
2385 machine_mode mode
, tree type ATTRIBUTE_UNUSED
,
2386 bool named ATTRIBUTE_UNUSED
)
2388 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2389 HOST_WIDE_INT param_size
;
2391 if (mode
== BLKmode
)
2393 param_size
= int_size_in_bytes (type
);
2394 gcc_assert (param_size
>= 0);
2397 param_size
= GET_MODE_SIZE (mode
);
2399 /* Convert to words (round up). */
2400 param_size
= (UNITS_PER_WORD
- 1 + param_size
) / UNITS_PER_WORD
;
2402 if (cum
->regs_used
< NUM_ARG_REGS
2403 && cum
->regs_used
+ param_size
> NUM_ARG_REGS
)
2404 return (NUM_ARG_REGS
- cum
->regs_used
) * UNITS_PER_WORD
;
2409 /* Update the data in CUM to advance over an argument of mode MODE
2410 and data type TYPE; TYPE is null for libcalls where that information
2411 may not be available. */
2414 nios2_function_arg_advance (cumulative_args_t cum_v
, machine_mode mode
,
2415 const_tree type ATTRIBUTE_UNUSED
,
2416 bool named ATTRIBUTE_UNUSED
)
2418 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2419 HOST_WIDE_INT param_size
;
2421 if (mode
== BLKmode
)
2423 param_size
= int_size_in_bytes (type
);
2424 gcc_assert (param_size
>= 0);
2427 param_size
= GET_MODE_SIZE (mode
);
2429 /* Convert to words (round up). */
2430 param_size
= (UNITS_PER_WORD
- 1 + param_size
) / UNITS_PER_WORD
;
2432 if (cum
->regs_used
+ param_size
> NUM_ARG_REGS
)
2433 cum
->regs_used
= NUM_ARG_REGS
;
2435 cum
->regs_used
+= param_size
;
2439 nios2_function_arg_padding (machine_mode mode
, const_tree type
)
2441 /* On little-endian targets, the first byte of every stack argument
2442 is passed in the first byte of the stack slot. */
2443 if (!BYTES_BIG_ENDIAN
)
2446 /* Otherwise, integral types are padded downward: the last byte of a
2447 stack argument is passed in the last byte of the stack slot. */
2449 ? INTEGRAL_TYPE_P (type
) || POINTER_TYPE_P (type
)
2450 : GET_MODE_CLASS (mode
) == MODE_INT
)
2453 /* Arguments smaller than a stack slot are padded downward. */
2454 if (mode
!= BLKmode
)
2455 return (GET_MODE_BITSIZE (mode
) >= PARM_BOUNDARY
) ? upward
: downward
;
2457 return ((int_size_in_bytes (type
) >= (PARM_BOUNDARY
/ BITS_PER_UNIT
))
2458 ? upward
: downward
);
2462 nios2_block_reg_padding (machine_mode mode
, tree type
,
2463 int first ATTRIBUTE_UNUSED
)
2465 return nios2_function_arg_padding (mode
, type
);
2468 /* Emit RTL insns to initialize the variable parts of a trampoline.
2469 FNADDR is an RTX for the address of the function's pure code.
2470 CXT is an RTX for the static chain value for the function.
2471 On Nios II, we handle this by a library call. */
2473 nios2_trampoline_init (rtx m_tramp
, tree fndecl
, rtx cxt
)
2475 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
2476 rtx ctx_reg
= force_reg (Pmode
, cxt
);
2477 rtx addr
= force_reg (Pmode
, XEXP (m_tramp
, 0));
2479 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, "__trampoline_setup"),
2480 LCT_NORMAL
, VOIDmode
, 3, addr
, Pmode
, fnaddr
, Pmode
,
2484 /* Implement TARGET_FUNCTION_VALUE. */
2486 nios2_function_value (const_tree ret_type
, const_tree fn ATTRIBUTE_UNUSED
,
2487 bool outgoing ATTRIBUTE_UNUSED
)
2489 return gen_rtx_REG (TYPE_MODE (ret_type
), FIRST_RETVAL_REGNO
);
2492 /* Implement TARGET_LIBCALL_VALUE. */
2494 nios2_libcall_value (machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
2496 return gen_rtx_REG (mode
, FIRST_RETVAL_REGNO
);
2499 /* Implement TARGET_FUNCTION_VALUE_REGNO_P. */
2501 nios2_function_value_regno_p (const unsigned int regno
)
2503 return regno
== FIRST_RETVAL_REGNO
;
2506 /* Implement TARGET_RETURN_IN_MEMORY. */
2508 nios2_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
2510 return (int_size_in_bytes (type
) > (2 * UNITS_PER_WORD
)
2511 || int_size_in_bytes (type
) == -1);
2514 /* TODO: It may be possible to eliminate the copyback and implement
2517 nios2_setup_incoming_varargs (cumulative_args_t cum_v
,
2518 machine_mode mode
, tree type
,
2519 int *pretend_size
, int second_time
)
2521 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2522 CUMULATIVE_ARGS local_cum
;
2523 cumulative_args_t local_cum_v
= pack_cumulative_args (&local_cum
);
2528 nios2_function_arg_advance (local_cum_v
, mode
, type
, 1);
2530 regs_to_push
= NUM_ARG_REGS
- local_cum
.regs_used
;
2532 if (!second_time
&& regs_to_push
> 0)
2534 rtx ptr
= virtual_incoming_args_rtx
;
2535 rtx mem
= gen_rtx_MEM (BLKmode
, ptr
);
2536 emit_insn (gen_blockage ());
2537 move_block_from_reg (local_cum
.regs_used
+ FIRST_ARG_REGNO
, mem
,
2539 emit_insn (gen_blockage ());
2542 pret_size
= regs_to_push
* UNITS_PER_WORD
;
2544 *pretend_size
= pret_size
;
2549 /* Init FPU builtins. */
2551 nios2_init_fpu_builtins (int start_code
)
2554 char builtin_name
[64] = "__builtin_custom_";
2555 unsigned int i
, n
= strlen ("__builtin_custom_");
2557 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
2559 snprintf (builtin_name
+ n
, sizeof (builtin_name
) - n
,
2560 "%s", N2FPU_NAME (i
));
2562 add_builtin_function (builtin_name
, nios2_ftype (N2FPU_FTCODE (i
)),
2563 start_code
+ i
, BUILT_IN_MD
, NULL
, NULL_TREE
);
2564 nios2_register_builtin_fndecl (start_code
+ i
, fndecl
);
2568 /* Helper function for expanding FPU builtins. */
2570 nios2_expand_fpu_builtin (tree exp
, unsigned int code
, rtx target
)
2572 struct expand_operand ops
[MAX_RECOG_OPERANDS
];
2573 enum insn_code icode
= N2FPU_ICODE (code
);
2574 int nargs
, argno
, opno
= 0;
2575 int num_operands
= N2FPU (code
).num_operands
;
2576 machine_mode dst_mode
= TYPE_MODE (TREE_TYPE (exp
));
2577 bool has_target_p
= (dst_mode
!= VOIDmode
);
2579 if (N2FPU_N (code
) < 0)
2580 fatal_error (input_location
,
2581 "Cannot call %<__builtin_custom_%s%> without specifying switch"
2582 " %<-mcustom-%s%>", N2FPU_NAME (code
), N2FPU_NAME (code
));
2584 create_output_operand (&ops
[opno
++], target
, dst_mode
);
2586 /* Subtract away the count of the VOID return, mainly for fwrx/fwry. */
2588 nargs
= call_expr_nargs (exp
);
2589 for (argno
= 0; argno
< nargs
; argno
++)
2591 tree arg
= CALL_EXPR_ARG (exp
, argno
);
2592 create_input_operand (&ops
[opno
++], expand_normal (arg
),
2593 TYPE_MODE (TREE_TYPE (arg
)));
2595 if (!maybe_expand_insn (icode
, num_operands
, ops
))
2597 error ("invalid argument to built-in function");
2598 return has_target_p
? gen_reg_rtx (ops
[0].mode
) : const0_rtx
;
2600 return has_target_p
? ops
[0].value
: const0_rtx
;
2603 /* Nios II has custom instruction built-in functions of the forms:
2606 __builtin_custom_nXX
2608 __builtin_custom_XnX
2609 __builtin_custom_XnXX
2611 where each X could be either 'i' (int), 'f' (float), or 'p' (void*).
2612 Therefore with 0-1 return values, and 0-2 arguments, we have a
2613 total of (3 + 1) * (1 + 3 + 9) == 52 custom builtin functions.
2615 #define NUM_CUSTOM_BUILTINS ((3 + 1) * (1 + 3 + 9))
2616 static char custom_builtin_name
[NUM_CUSTOM_BUILTINS
][5];
2619 nios2_init_custom_builtins (int start_code
)
2621 tree builtin_ftype
, ret_type
, fndecl
;
2622 char builtin_name
[32] = "__builtin_custom_";
2623 int n
= strlen ("__builtin_custom_");
2624 int builtin_code
= 0;
2625 int lhs
, rhs1
, rhs2
;
2627 struct { tree type
; const char *c
; } op
[4];
2628 /* z */ op
[0].c
= ""; op
[0].type
= NULL_TREE
;
2629 /* f */ op
[1].c
= "f"; op
[1].type
= float_type_node
;
2630 /* i */ op
[2].c
= "i"; op
[2].type
= integer_type_node
;
2631 /* p */ op
[3].c
= "p"; op
[3].type
= ptr_type_node
;
2633 /* We enumerate through the possible operand types to create all the
2634 __builtin_custom_XnXX function tree types. Note that these may slightly
2635 overlap with the function types created for other fixed builtins. */
2637 for (lhs
= 0; lhs
< 4; lhs
++)
2638 for (rhs1
= 0; rhs1
< 4; rhs1
++)
2639 for (rhs2
= 0; rhs2
< 4; rhs2
++)
2641 if (rhs1
== 0 && rhs2
!= 0)
2643 ret_type
= (op
[lhs
].type
? op
[lhs
].type
: void_type_node
);
2645 = build_function_type_list (ret_type
, integer_type_node
,
2646 op
[rhs1
].type
, op
[rhs2
].type
,
2648 snprintf (builtin_name
+ n
, 32 - n
, "%sn%s%s",
2649 op
[lhs
].c
, op
[rhs1
].c
, op
[rhs2
].c
);
2650 /* Save copy of parameter string into custom_builtin_name[]. */
2651 strncpy (custom_builtin_name
[builtin_code
], builtin_name
+ n
, 5);
2653 add_builtin_function (builtin_name
, builtin_ftype
,
2654 start_code
+ builtin_code
,
2655 BUILT_IN_MD
, NULL
, NULL_TREE
);
2656 nios2_register_builtin_fndecl (start_code
+ builtin_code
, fndecl
);
2661 /* Helper function for expanding custom builtins. */
2663 nios2_expand_custom_builtin (tree exp
, unsigned int index
, rtx target
)
2665 bool has_target_p
= (TREE_TYPE (exp
) != void_type_node
);
2666 machine_mode tmode
= VOIDmode
;
2668 rtx value
, insn
, unspec_args
[3];
2674 tmode
= TYPE_MODE (TREE_TYPE (exp
));
2675 if (!target
|| GET_MODE (target
) != tmode
2677 target
= gen_reg_rtx (tmode
);
2680 nargs
= call_expr_nargs (exp
);
2681 for (argno
= 0; argno
< nargs
; argno
++)
2683 arg
= CALL_EXPR_ARG (exp
, argno
);
2684 value
= expand_normal (arg
);
2685 unspec_args
[argno
] = value
;
2688 if (!custom_insn_opcode (value
, VOIDmode
))
2689 error ("custom instruction opcode must be compile time "
2690 "constant in the range 0-255 for __builtin_custom_%s",
2691 custom_builtin_name
[index
]);
2694 /* For other arguments, force into a register. */
2695 unspec_args
[argno
] = force_reg (TYPE_MODE (TREE_TYPE (arg
)),
2696 unspec_args
[argno
]);
2698 /* Fill remaining unspec operands with zero. */
2699 for (; argno
< 3; argno
++)
2700 unspec_args
[argno
] = const0_rtx
;
2702 insn
= (has_target_p
2703 ? gen_rtx_SET (target
,
2704 gen_rtx_UNSPEC_VOLATILE (tmode
,
2705 gen_rtvec_v (3, unspec_args
),
2706 UNSPECV_CUSTOM_XNXX
))
2707 : gen_rtx_UNSPEC_VOLATILE (VOIDmode
, gen_rtvec_v (3, unspec_args
),
2708 UNSPECV_CUSTOM_NXX
));
2710 return has_target_p
? target
: const0_rtx
;
2716 /* Main definition of built-in functions. Nios II has a small number of fixed
2717 builtins, plus a large number of FPU insn builtins, and builtins for
2718 generating custom instructions. */
2720 struct nios2_builtin_desc
2722 enum insn_code icode
;
2723 enum nios2_ftcode ftype
;
2727 #define N2_BUILTINS \
2728 N2_BUILTIN_DEF (sync, N2_FTYPE_VOID_VOID) \
2729 N2_BUILTIN_DEF (ldbio, N2_FTYPE_SI_CVPTR) \
2730 N2_BUILTIN_DEF (ldbuio, N2_FTYPE_UI_CVPTR) \
2731 N2_BUILTIN_DEF (ldhio, N2_FTYPE_SI_CVPTR) \
2732 N2_BUILTIN_DEF (ldhuio, N2_FTYPE_UI_CVPTR) \
2733 N2_BUILTIN_DEF (ldwio, N2_FTYPE_SI_CVPTR) \
2734 N2_BUILTIN_DEF (stbio, N2_FTYPE_VOID_VPTR_SI) \
2735 N2_BUILTIN_DEF (sthio, N2_FTYPE_VOID_VPTR_SI) \
2736 N2_BUILTIN_DEF (stwio, N2_FTYPE_VOID_VPTR_SI) \
2737 N2_BUILTIN_DEF (rdctl, N2_FTYPE_SI_SI) \
2738 N2_BUILTIN_DEF (wrctl, N2_FTYPE_VOID_SI_SI)
2740 enum nios2_builtin_code
{
2741 #define N2_BUILTIN_DEF(name, ftype) NIOS2_BUILTIN_ ## name,
2743 #undef N2_BUILTIN_DEF
2744 NUM_FIXED_NIOS2_BUILTINS
2747 static const struct nios2_builtin_desc nios2_builtins
[] = {
2748 #define N2_BUILTIN_DEF(name, ftype) \
2749 { CODE_FOR_ ## name, ftype, "__builtin_" #name },
2751 #undef N2_BUILTIN_DEF
2754 /* Start/ends of FPU/custom insn builtin index ranges. */
2755 static unsigned int nios2_fpu_builtin_base
;
2756 static unsigned int nios2_custom_builtin_base
;
2757 static unsigned int nios2_custom_builtin_end
;
2759 /* Implement TARGET_INIT_BUILTINS. */
2761 nios2_init_builtins (void)
2765 /* Initialize fixed builtins. */
2766 for (i
= 0; i
< ARRAY_SIZE (nios2_builtins
); i
++)
2768 const struct nios2_builtin_desc
*d
= &nios2_builtins
[i
];
2770 add_builtin_function (d
->name
, nios2_ftype (d
->ftype
), i
,
2771 BUILT_IN_MD
, NULL
, NULL
);
2772 nios2_register_builtin_fndecl (i
, fndecl
);
2775 /* Initialize FPU builtins. */
2776 nios2_fpu_builtin_base
= ARRAY_SIZE (nios2_builtins
);
2777 nios2_init_fpu_builtins (nios2_fpu_builtin_base
);
2779 /* Initialize custom insn builtins. */
2780 nios2_custom_builtin_base
2781 = nios2_fpu_builtin_base
+ ARRAY_SIZE (nios2_fpu_insn
);
2782 nios2_custom_builtin_end
2783 = nios2_custom_builtin_base
+ NUM_CUSTOM_BUILTINS
;
2784 nios2_init_custom_builtins (nios2_custom_builtin_base
);
2787 /* Array of fndecls for TARGET_BUILTIN_DECL. */
2788 #define NIOS2_NUM_BUILTINS \
2789 (ARRAY_SIZE (nios2_builtins) + ARRAY_SIZE (nios2_fpu_insn) + NUM_CUSTOM_BUILTINS)
2790 static GTY(()) tree nios2_builtin_decls
[NIOS2_NUM_BUILTINS
];
2793 nios2_register_builtin_fndecl (unsigned code
, tree fndecl
)
2795 nios2_builtin_decls
[code
] = fndecl
;
2798 /* Implement TARGET_BUILTIN_DECL. */
2800 nios2_builtin_decl (unsigned code
, bool initialize_p ATTRIBUTE_UNUSED
)
2802 gcc_assert (nios2_custom_builtin_end
== ARRAY_SIZE (nios2_builtin_decls
));
2804 if (code
>= nios2_custom_builtin_end
)
2805 return error_mark_node
;
2807 if (code
>= nios2_fpu_builtin_base
2808 && code
< nios2_custom_builtin_base
2809 && ! N2FPU_ENABLED_P (code
- nios2_fpu_builtin_base
))
2810 return error_mark_node
;
2812 return nios2_builtin_decls
[code
];
2816 /* Low-level built-in expand routine. */
2818 nios2_expand_builtin_insn (const struct nios2_builtin_desc
*d
, int n
,
2819 struct expand_operand
*ops
, bool has_target_p
)
2821 if (maybe_expand_insn (d
->icode
, n
, ops
))
2822 return has_target_p
? ops
[0].value
: const0_rtx
;
2825 error ("invalid argument to built-in function %s", d
->name
);
2826 return has_target_p
? gen_reg_rtx (ops
[0].mode
) : const0_rtx
;
2830 /* Expand ldio/stio form load-store instruction builtins. */
2832 nios2_expand_ldstio_builtin (tree exp
, rtx target
,
2833 const struct nios2_builtin_desc
*d
)
2837 struct expand_operand ops
[MAX_RECOG_OPERANDS
];
2838 machine_mode mode
= insn_data
[d
->icode
].operand
[0].mode
;
2840 addr
= expand_normal (CALL_EXPR_ARG (exp
, 0));
2841 mem
= gen_rtx_MEM (mode
, addr
);
2843 if (insn_data
[d
->icode
].operand
[0].allows_mem
)
2846 val
= expand_normal (CALL_EXPR_ARG (exp
, 1));
2847 if (CONST_INT_P (val
))
2848 val
= force_reg (mode
, gen_int_mode (INTVAL (val
), mode
));
2849 val
= simplify_gen_subreg (mode
, val
, GET_MODE (val
), 0);
2850 create_output_operand (&ops
[0], mem
, mode
);
2851 create_input_operand (&ops
[1], val
, mode
);
2852 has_target_p
= false;
2857 create_output_operand (&ops
[0], target
, mode
);
2858 create_input_operand (&ops
[1], mem
, mode
);
2859 has_target_p
= true;
2861 return nios2_expand_builtin_insn (d
, 2, ops
, has_target_p
);
2864 /* Expand rdctl/wrctl builtins. */
2866 nios2_expand_rdwrctl_builtin (tree exp
, rtx target
,
2867 const struct nios2_builtin_desc
*d
)
2869 bool has_target_p
= (insn_data
[d
->icode
].operand
[0].predicate
2870 == register_operand
);
2871 rtx ctlcode
= expand_normal (CALL_EXPR_ARG (exp
, 0));
2872 struct expand_operand ops
[MAX_RECOG_OPERANDS
];
2873 if (!rdwrctl_operand (ctlcode
, VOIDmode
))
2875 error ("Control register number must be in range 0-31 for %s",
2877 return has_target_p
? gen_reg_rtx (SImode
) : const0_rtx
;
2881 create_output_operand (&ops
[0], target
, SImode
);
2882 create_integer_operand (&ops
[1], INTVAL (ctlcode
));
2886 rtx val
= expand_normal (CALL_EXPR_ARG (exp
, 1));
2887 create_integer_operand (&ops
[0], INTVAL (ctlcode
));
2888 create_input_operand (&ops
[1], val
, SImode
);
2890 return nios2_expand_builtin_insn (d
, 2, ops
, has_target_p
);
2893 /* Implement TARGET_EXPAND_BUILTIN. Expand an expression EXP that calls
2894 a built-in function, with result going to TARGET if that's convenient
2895 (and in mode MODE if that's convenient).
2896 SUBTARGET may be used as the target for computing one of EXP's operands.
2897 IGNORE is nonzero if the value is to be ignored. */
2900 nios2_expand_builtin (tree exp
, rtx target
, rtx subtarget ATTRIBUTE_UNUSED
,
2901 machine_mode mode ATTRIBUTE_UNUSED
,
2902 int ignore ATTRIBUTE_UNUSED
)
2904 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
2905 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
2907 if (fcode
< nios2_fpu_builtin_base
)
2909 const struct nios2_builtin_desc
*d
= &nios2_builtins
[fcode
];
2913 case NIOS2_BUILTIN_sync
:
2914 emit_insn (gen_sync ());
2917 case NIOS2_BUILTIN_ldbio
:
2918 case NIOS2_BUILTIN_ldbuio
:
2919 case NIOS2_BUILTIN_ldhio
:
2920 case NIOS2_BUILTIN_ldhuio
:
2921 case NIOS2_BUILTIN_ldwio
:
2922 case NIOS2_BUILTIN_stbio
:
2923 case NIOS2_BUILTIN_sthio
:
2924 case NIOS2_BUILTIN_stwio
:
2925 return nios2_expand_ldstio_builtin (exp
, target
, d
);
2927 case NIOS2_BUILTIN_rdctl
:
2928 case NIOS2_BUILTIN_wrctl
:
2929 return nios2_expand_rdwrctl_builtin (exp
, target
, d
);
2935 else if (fcode
< nios2_custom_builtin_base
)
2936 /* FPU builtin range. */
2937 return nios2_expand_fpu_builtin (exp
, fcode
- nios2_fpu_builtin_base
,
2939 else if (fcode
< nios2_custom_builtin_end
)
2940 /* Custom insn builtin range. */
2941 return nios2_expand_custom_builtin (exp
, fcode
- nios2_custom_builtin_base
,
2947 /* Implement TARGET_INIT_LIBFUNCS. */
2949 nios2_init_libfuncs (void)
2951 /* For Linux, we have access to kernel support for atomic operations. */
2952 if (TARGET_LINUX_ABI
)
2953 init_sync_libfuncs (UNITS_PER_WORD
);
2958 /* Register a custom code use, and signal error if a conflict was found. */
2960 nios2_register_custom_code (unsigned int N
, enum nios2_ccs_code status
,
2963 gcc_assert (N
<= 255);
2965 if (status
== CCS_FPU
)
2967 if (custom_code_status
[N
] == CCS_FPU
&& index
!= custom_code_index
[N
])
2969 custom_code_conflict
= true;
2970 error ("switch %<-mcustom-%s%> conflicts with switch %<-mcustom-%s%>",
2971 N2FPU_NAME (custom_code_index
[N
]), N2FPU_NAME (index
));
2973 else if (custom_code_status
[N
] == CCS_BUILTIN_CALL
)
2975 custom_code_conflict
= true;
2976 error ("call to %<__builtin_custom_%s%> conflicts with switch "
2977 "%<-mcustom-%s%>", custom_builtin_name
[custom_code_index
[N
]],
2978 N2FPU_NAME (index
));
2981 else if (status
== CCS_BUILTIN_CALL
)
2983 if (custom_code_status
[N
] == CCS_FPU
)
2985 custom_code_conflict
= true;
2986 error ("call to %<__builtin_custom_%s%> conflicts with switch "
2987 "%<-mcustom-%s%>", custom_builtin_name
[index
],
2988 N2FPU_NAME (custom_code_index
[N
]));
2992 /* Note that code conflicts between different __builtin_custom_xnxx
2993 calls are not checked. */
2999 custom_code_status
[N
] = status
;
3000 custom_code_index
[N
] = index
;
3003 /* Mark a custom code as not in use. */
3005 nios2_deregister_custom_code (unsigned int N
)
3009 custom_code_status
[N
] = CCS_UNUSED
;
3010 custom_code_index
[N
] = 0;
3014 /* Target attributes can affect per-function option state, so we need to
3015 save/restore the custom code tracking info using the
3016 TARGET_OPTION_SAVE/TARGET_OPTION_RESTORE hooks. */
3019 nios2_option_save (struct cl_target_option
*ptr
,
3020 struct gcc_options
*opts ATTRIBUTE_UNUSED
)
3023 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
3024 ptr
->saved_fpu_custom_code
[i
] = N2FPU_N (i
);
3025 memcpy (ptr
->saved_custom_code_status
, custom_code_status
,
3026 sizeof (custom_code_status
));
3027 memcpy (ptr
->saved_custom_code_index
, custom_code_index
,
3028 sizeof (custom_code_index
));
3032 nios2_option_restore (struct gcc_options
*opts ATTRIBUTE_UNUSED
,
3033 struct cl_target_option
*ptr
)
3036 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
3037 N2FPU_N (i
) = ptr
->saved_fpu_custom_code
[i
];
3038 memcpy (custom_code_status
, ptr
->saved_custom_code_status
,
3039 sizeof (custom_code_status
));
3040 memcpy (custom_code_index
, ptr
->saved_custom_code_index
,
3041 sizeof (custom_code_index
));
3044 /* Inner function to process the attribute((target(...))), take an argument and
3045 set the current options from the argument. If we have a list, recursively
3046 go over the list. */
3049 nios2_valid_target_attribute_rec (tree args
)
3051 if (TREE_CODE (args
) == TREE_LIST
)
3054 for (; args
; args
= TREE_CHAIN (args
))
3055 if (TREE_VALUE (args
)
3056 && !nios2_valid_target_attribute_rec (TREE_VALUE (args
)))
3060 else if (TREE_CODE (args
) == STRING_CST
)
3062 char *argstr
= ASTRDUP (TREE_STRING_POINTER (args
));
3063 while (argstr
&& *argstr
!= '\0')
3065 bool no_opt
= false, end_p
= false;
3066 char *eq
= NULL
, *p
;
3067 while (ISSPACE (*argstr
))
3070 while (*p
!= '\0' && *p
!= ',')
3072 if (!eq
&& *p
== '=')
3082 if (!strncmp (argstr
, "no-", 3))
3087 if (!strncmp (argstr
, "custom-fpu-cfg", 14))
3092 error ("custom-fpu-cfg option does not support %<no-%>");
3097 error ("custom-fpu-cfg option requires configuration"
3101 /* Increment and skip whitespace. */
3102 while (ISSPACE (*(++eq
))) ;
3103 /* Decrement and skip to before any trailing whitespace. */
3104 while (ISSPACE (*(--end_eq
))) ;
3106 nios2_handle_custom_fpu_cfg (eq
, end_eq
+ 1, true);
3108 else if (!strncmp (argstr
, "custom-", 7))
3112 for (i
= 0; i
< ARRAY_SIZE (nios2_fpu_insn
); i
++)
3113 if (!strncmp (argstr
+ 7, N2FPU_NAME (i
),
3114 strlen (N2FPU_NAME (i
))))
3126 error ("%<no-custom-%s%> does not accept arguments",
3130 /* Disable option by setting to -1. */
3131 nios2_deregister_custom_code (N2FPU_N (code
));
3132 N2FPU_N (code
) = -1;
3138 while (ISSPACE (*(++eq
))) ;
3141 error ("%<custom-%s=%> requires argument",
3145 for (t
= eq
; t
!= p
; ++t
)
3151 error ("`custom-%s=' argument requires "
3152 "numeric digits", N2FPU_NAME (code
));
3156 /* Set option to argument. */
3157 N2FPU_N (code
) = atoi (eq
);
3158 nios2_handle_custom_fpu_insn_option (code
);
3163 error ("%<custom-%s=%> is not recognised as FPU instruction",
3170 error ("%<%s%> is unknown", argstr
);
3185 /* Return a TARGET_OPTION_NODE tree of the target options listed or NULL. */
3188 nios2_valid_target_attribute_tree (tree args
)
3190 if (!nios2_valid_target_attribute_rec (args
))
3192 nios2_custom_check_insns ();
3193 return build_target_option_node (&global_options
);
3196 /* Hook to validate attribute((target("string"))). */
3199 nios2_valid_target_attribute_p (tree fndecl
, tree
ARG_UNUSED (name
),
3200 tree args
, int ARG_UNUSED (flags
))
3202 struct cl_target_option cur_target
;
3204 tree old_optimize
= build_optimization_node (&global_options
);
3205 tree new_target
, new_optimize
;
3206 tree func_optimize
= DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl
);
3208 /* If the function changed the optimization levels as well as setting target
3209 options, start with the optimizations specified. */
3210 if (func_optimize
&& func_optimize
!= old_optimize
)
3211 cl_optimization_restore (&global_options
,
3212 TREE_OPTIMIZATION (func_optimize
));
3214 /* The target attributes may also change some optimization flags, so update
3215 the optimization options if necessary. */
3216 cl_target_option_save (&cur_target
, &global_options
);
3217 new_target
= nios2_valid_target_attribute_tree (args
);
3218 new_optimize
= build_optimization_node (&global_options
);
3225 DECL_FUNCTION_SPECIFIC_TARGET (fndecl
) = new_target
;
3227 if (old_optimize
!= new_optimize
)
3228 DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl
) = new_optimize
;
3231 cl_target_option_restore (&global_options
, &cur_target
);
3233 if (old_optimize
!= new_optimize
)
3234 cl_optimization_restore (&global_options
,
3235 TREE_OPTIMIZATION (old_optimize
));
3239 /* Remember the last target of nios2_set_current_function. */
3240 static GTY(()) tree nios2_previous_fndecl
;
3242 /* Establish appropriate back-end context for processing the function
3243 FNDECL. The argument might be NULL to indicate processing at top
3244 level, outside of any function scope. */
3246 nios2_set_current_function (tree fndecl
)
3248 tree old_tree
= (nios2_previous_fndecl
3249 ? DECL_FUNCTION_SPECIFIC_TARGET (nios2_previous_fndecl
)
3252 tree new_tree
= (fndecl
3253 ? DECL_FUNCTION_SPECIFIC_TARGET (fndecl
)
3256 if (fndecl
&& fndecl
!= nios2_previous_fndecl
)
3258 nios2_previous_fndecl
= fndecl
;
3259 if (old_tree
== new_tree
)
3264 cl_target_option_restore (&global_options
,
3265 TREE_TARGET_OPTION (new_tree
));
3271 struct cl_target_option
*def
3272 = TREE_TARGET_OPTION (target_option_current_node
);
3274 cl_target_option_restore (&global_options
, def
);
3280 /* Hook to validate the current #pragma GCC target and set the FPU custom
3281 code option state. If ARGS is NULL, then POP_TARGET is used to reset
3284 nios2_pragma_target_parse (tree args
, tree pop_target
)
3289 cur_tree
= ((pop_target
)
3291 : target_option_default_node
);
3292 cl_target_option_restore (&global_options
,
3293 TREE_TARGET_OPTION (cur_tree
));
3297 cur_tree
= nios2_valid_target_attribute_tree (args
);
3302 target_option_current_node
= cur_tree
;
3306 /* Implement TARGET_MERGE_DECL_ATTRIBUTES.
3307 We are just using this hook to add some additional error checking to
3308 the default behavior. GCC does not provide a target hook for merging
3309 the target options, and only correctly handles merging empty vs non-empty
3310 option data; see merge_decls() in c-decl.c.
3311 So here we require either that at least one of the decls has empty
3312 target options, or that the target options/data be identical. */
3314 nios2_merge_decl_attributes (tree olddecl
, tree newdecl
)
3316 tree oldopts
= lookup_attribute ("target", DECL_ATTRIBUTES (olddecl
));
3317 tree newopts
= lookup_attribute ("target", DECL_ATTRIBUTES (newdecl
));
3318 if (newopts
&& oldopts
&& newopts
!= oldopts
)
3320 tree oldtree
= DECL_FUNCTION_SPECIFIC_TARGET (olddecl
);
3321 tree newtree
= DECL_FUNCTION_SPECIFIC_TARGET (newdecl
);
3322 if (oldtree
&& newtree
&& oldtree
!= newtree
)
3324 struct cl_target_option
*olddata
= TREE_TARGET_OPTION (oldtree
);
3325 struct cl_target_option
*newdata
= TREE_TARGET_OPTION (newtree
);
3326 if (olddata
!= newdata
3327 && memcmp (olddata
, newdata
, sizeof (struct cl_target_option
)))
3328 error ("%qE redeclared with conflicting %qs attributes",
3329 DECL_NAME (newdecl
), "target");
3332 return merge_attributes (DECL_ATTRIBUTES (olddecl
),
3333 DECL_ATTRIBUTES (newdecl
));
3336 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. */
3338 nios2_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3339 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3342 rtx this_rtx
, funexp
;
3345 /* Pretend to be a post-reload pass while generating rtl. */
3346 reload_completed
= 1;
3349 nios2_load_pic_register ();
3351 /* Mark the end of the (empty) prologue. */
3352 emit_note (NOTE_INSN_PROLOGUE_END
);
3354 /* Find the "this" pointer. If the function returns a structure,
3355 the structure return pointer is in $5. */
3356 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3357 this_rtx
= gen_rtx_REG (Pmode
, FIRST_ARG_REGNO
+ 1);
3359 this_rtx
= gen_rtx_REG (Pmode
, FIRST_ARG_REGNO
);
3361 /* Add DELTA to THIS_RTX. */
3362 nios2_emit_add_constant (this_rtx
, delta
);
3364 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
3369 tmp
= gen_rtx_REG (Pmode
, 2);
3370 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, this_rtx
));
3371 nios2_emit_add_constant (tmp
, vcall_offset
);
3372 emit_move_insn (tmp
, gen_rtx_MEM (Pmode
, tmp
));
3373 emit_insn (gen_add2_insn (this_rtx
, tmp
));
3376 /* Generate a tail call to the target function. */
3377 if (!TREE_USED (function
))
3379 assemble_external (function
);
3380 TREE_USED (function
) = 1;
3382 funexp
= XEXP (DECL_RTL (function
), 0);
3383 /* Function address needs to be constructed under PIC,
3384 provide r2 to use here. */
3385 nios2_adjust_call_address (&funexp
, gen_rtx_REG (Pmode
, 2));
3386 insn
= emit_call_insn (gen_sibcall_internal (funexp
, const0_rtx
));
3387 SIBLING_CALL_P (insn
) = 1;
3389 /* Run just enough of rest_of_compilation to get the insns emitted.
3390 There's not really enough bulk here to make other passes such as
3391 instruction scheduling worth while. Note that use_thunk calls
3392 assemble_start_function and assemble_end_function. */
3393 insn
= get_insns ();
3394 shorten_branches (insn
);
3395 final_start_function (insn
, file
, 1);
3396 final (insn
, file
, 1);
3397 final_end_function ();
3399 /* Stop pretending to be a post-reload pass. */
3400 reload_completed
= 0;
3404 /* Initialize the GCC target structure. */
3405 #undef TARGET_ASM_FUNCTION_PROLOGUE
3406 #define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue
3408 #undef TARGET_IN_SMALL_DATA_P
3409 #define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p
3411 #undef TARGET_SECTION_TYPE_FLAGS
3412 #define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags
3414 #undef TARGET_INIT_BUILTINS
3415 #define TARGET_INIT_BUILTINS nios2_init_builtins
3416 #undef TARGET_EXPAND_BUILTIN
3417 #define TARGET_EXPAND_BUILTIN nios2_expand_builtin
3418 #undef TARGET_BUILTIN_DECL
3419 #define TARGET_BUILTIN_DECL nios2_builtin_decl
3421 #undef TARGET_INIT_LIBFUNCS
3422 #define TARGET_INIT_LIBFUNCS nios2_init_libfuncs
3424 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
3425 #define TARGET_FUNCTION_OK_FOR_SIBCALL hook_bool_tree_tree_true
3427 #undef TARGET_CAN_ELIMINATE
3428 #define TARGET_CAN_ELIMINATE nios2_can_eliminate
3430 #undef TARGET_FUNCTION_ARG
3431 #define TARGET_FUNCTION_ARG nios2_function_arg
3433 #undef TARGET_FUNCTION_ARG_ADVANCE
3434 #define TARGET_FUNCTION_ARG_ADVANCE nios2_function_arg_advance
3436 #undef TARGET_ARG_PARTIAL_BYTES
3437 #define TARGET_ARG_PARTIAL_BYTES nios2_arg_partial_bytes
3439 #undef TARGET_TRAMPOLINE_INIT
3440 #define TARGET_TRAMPOLINE_INIT nios2_trampoline_init
3442 #undef TARGET_FUNCTION_VALUE
3443 #define TARGET_FUNCTION_VALUE nios2_function_value
3445 #undef TARGET_LIBCALL_VALUE
3446 #define TARGET_LIBCALL_VALUE nios2_libcall_value
3448 #undef TARGET_FUNCTION_VALUE_REGNO_P
3449 #define TARGET_FUNCTION_VALUE_REGNO_P nios2_function_value_regno_p
3451 #undef TARGET_RETURN_IN_MEMORY
3452 #define TARGET_RETURN_IN_MEMORY nios2_return_in_memory
3454 #undef TARGET_PROMOTE_PROTOTYPES
3455 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
3457 #undef TARGET_SETUP_INCOMING_VARARGS
3458 #define TARGET_SETUP_INCOMING_VARARGS nios2_setup_incoming_varargs
3460 #undef TARGET_MUST_PASS_IN_STACK
3461 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
3463 #undef TARGET_LEGITIMATE_CONSTANT_P
3464 #define TARGET_LEGITIMATE_CONSTANT_P nios2_legitimate_constant_p
3466 #undef TARGET_LEGITIMIZE_ADDRESS
3467 #define TARGET_LEGITIMIZE_ADDRESS nios2_legitimize_address
3469 #undef TARGET_DELEGITIMIZE_ADDRESS
3470 #define TARGET_DELEGITIMIZE_ADDRESS nios2_delegitimize_address
3472 #undef TARGET_LEGITIMATE_ADDRESS_P
3473 #define TARGET_LEGITIMATE_ADDRESS_P nios2_legitimate_address_p
3475 #undef TARGET_PREFERRED_RELOAD_CLASS
3476 #define TARGET_PREFERRED_RELOAD_CLASS nios2_preferred_reload_class
3478 #undef TARGET_RTX_COSTS
3479 #define TARGET_RTX_COSTS nios2_rtx_costs
3481 #undef TARGET_HAVE_TLS
3482 #define TARGET_HAVE_TLS TARGET_LINUX_ABI
3484 #undef TARGET_CANNOT_FORCE_CONST_MEM
3485 #define TARGET_CANNOT_FORCE_CONST_MEM nios2_cannot_force_const_mem
3487 #undef TARGET_ASM_OUTPUT_DWARF_DTPREL
3488 #define TARGET_ASM_OUTPUT_DWARF_DTPREL nios2_output_dwarf_dtprel
3490 #undef TARGET_PRINT_OPERAND
3491 #define TARGET_PRINT_OPERAND nios2_print_operand
3493 #undef TARGET_PRINT_OPERAND_ADDRESS
3494 #define TARGET_PRINT_OPERAND_ADDRESS nios2_print_operand_address
3496 #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
3497 #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA nios2_output_addr_const_extra
3499 #undef TARGET_ASM_FILE_END
3500 #define TARGET_ASM_FILE_END nios2_asm_file_end
3502 #undef TARGET_OPTION_OVERRIDE
3503 #define TARGET_OPTION_OVERRIDE nios2_option_override
3505 #undef TARGET_OPTION_SAVE
3506 #define TARGET_OPTION_SAVE nios2_option_save
3508 #undef TARGET_OPTION_RESTORE
3509 #define TARGET_OPTION_RESTORE nios2_option_restore
3511 #undef TARGET_SET_CURRENT_FUNCTION
3512 #define TARGET_SET_CURRENT_FUNCTION nios2_set_current_function
3514 #undef TARGET_OPTION_VALID_ATTRIBUTE_P
3515 #define TARGET_OPTION_VALID_ATTRIBUTE_P nios2_valid_target_attribute_p
3517 #undef TARGET_OPTION_PRAGMA_PARSE
3518 #define TARGET_OPTION_PRAGMA_PARSE nios2_pragma_target_parse
3520 #undef TARGET_MERGE_DECL_ATTRIBUTES
3521 #define TARGET_MERGE_DECL_ATTRIBUTES nios2_merge_decl_attributes
3523 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3524 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
3525 hook_bool_const_tree_hwi_hwi_const_tree_true
3527 #undef TARGET_ASM_OUTPUT_MI_THUNK
3528 #define TARGET_ASM_OUTPUT_MI_THUNK nios2_asm_output_mi_thunk
3530 struct gcc_target targetm
= TARGET_INITIALIZER
;
3532 #include "gt-nios2.h"