111
|
1 /* Output routines for CR16 processor.
|
131
|
2 Copyright (C) 2012-2018 Free Software Foundation, Inc.
|
111
|
3 Contributed by KPIT Cummins Infosystems Limited.
|
|
4
|
|
5 This file is part of GCC.
|
|
6
|
|
7 GCC is free software; you can redistribute it and/or modify it
|
|
8 under the terms of the GNU General Public License as published
|
|
9 by the Free Software Foundation; either version 3, or (at your
|
|
10 option) any later version.
|
|
11
|
|
12 GCC is distributed in the hope that it will be useful, but WITHOUT
|
|
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
15 License for more details.
|
|
16
|
|
17 You should have received a copy of the GNU General Public License
|
|
18 along with GCC; see the file COPYING3. If not see
|
|
19 <http://www.gnu.org/licenses/>. */
|
|
20
|
131
|
21 #define IN_TARGET_CODE 1
|
|
22
|
111
|
23 #include "config.h"
|
|
24 #include "system.h"
|
|
25 #include "coretypes.h"
|
|
26 #include "backend.h"
|
|
27 #include "target.h"
|
|
28 #include "rtl.h"
|
|
29 #include "tree.h"
|
|
30 #include "stringpool.h"
|
|
31 #include "attribs.h"
|
|
32 #include "df.h"
|
|
33 #include "memmodel.h"
|
|
34 #include "tm_p.h"
|
|
35 #include "regs.h"
|
|
36 #include "emit-rtl.h"
|
|
37 #include "diagnostic-core.h"
|
|
38 #include "stor-layout.h"
|
|
39 #include "calls.h"
|
|
40 #include "conditions.h"
|
|
41 #include "output.h"
|
|
42 #include "expr.h"
|
|
43 #include "builtins.h"
|
|
44
|
|
45 /* This file should be included last. */
|
|
46 #include "target-def.h"
|
|
47
|
|
48 /* Definitions. */
|
|
49
|
|
50 /* Maximum number of register used for passing parameters. */
|
|
51 #define MAX_REG_FOR_PASSING_ARGS 6
|
|
52
|
|
53 /* Minimum number register used for passing parameters. */
|
|
54 #define MIN_REG_FOR_PASSING_ARGS 2
|
|
55
|
|
56 /* The maximum count of words supported in the assembly of the architecture in
|
|
57 a push/pop instruction. */
|
|
58 #define MAX_COUNT 8
|
|
59
|
|
60 /* Predicate is true if the current function is a 'noreturn' function,
|
|
61 i.e. it is qualified as volatile. */
|
|
62 #define FUNC_IS_NORETURN_P(decl) (TREE_THIS_VOLATILE (decl))
|
|
63
|
|
64 /* Predicate that holds when we need to save registers even for 'noreturn'
|
|
65 functions, to accommodate for unwinding. */
|
|
66 #define MUST_SAVE_REGS_P() \
|
|
67 (flag_unwind_tables || (flag_exceptions && !UI_SJLJ))
|
|
68
|
|
69 /* Nonzero if the rtx X is a signed const int of n bits. */
|
|
70 #define RTX_SIGNED_INT_FITS_N_BITS(X, n) \
|
|
71 ((GET_CODE (X) == CONST_INT \
|
|
72 && SIGNED_INT_FITS_N_BITS (INTVAL (X), n)) ? 1 : 0)
|
|
73
|
|
74 /* Nonzero if the rtx X is an unsigned const int of n bits. */
|
|
75 #define RTX_UNSIGNED_INT_FITS_N_BITS(X, n) \
|
|
76 ((GET_CODE (X) == CONST_INT \
|
|
77 && UNSIGNED_INT_FITS_N_BITS (INTVAL (X), n)) ? 1 : 0)
|
|
78
|
|
79 /* Structure for stack computations. */
|
|
80
|
|
81 /* variable definitions in the struture
|
|
82 args_size Number of bytes saved on the stack for local
|
|
83 variables
|
|
84
|
|
85 reg_size Number of bytes saved on the stack for
|
|
86 non-scratch registers
|
|
87
|
|
88 total_size The sum of 2 sizes: locals vars and padding byte
|
|
89 for saving the registers. Used in expand_prologue()
|
|
90 and expand_epilogue()
|
|
91
|
|
92 last_reg_to_save Will hold the number of the last register the
|
|
93 prologue saves, -1 if no register is saved
|
|
94
|
|
95 save_regs[16] Each object in the array is a register number.
|
|
96 Mark 1 for registers that need to be saved
|
|
97
|
|
98 num_regs Number of registers saved
|
|
99
|
|
100 initialized Non-zero if frame size already calculated, not
|
|
101 used yet
|
|
102
|
|
103 function_makes_calls Does the function make calls ? not used yet. */
|
|
104
|
|
105 struct cr16_frame_info
|
|
106 {
|
|
107 unsigned long var_size;
|
|
108 unsigned long args_size;
|
|
109 unsigned int reg_size;
|
|
110 unsigned long total_size;
|
|
111 long last_reg_to_save;
|
|
112 long save_regs[FIRST_PSEUDO_REGISTER];
|
|
113 int num_regs;
|
|
114 int initialized;
|
|
115 int function_makes_calls;
|
|
116 };
|
|
117
|
|
118 /* Current frame information calculated by cr16_compute_frame_size. */
|
|
119 static struct cr16_frame_info current_frame_info;
|
|
120
|
|
121 /* Static Variables. */
|
|
122
|
|
123 /* Data model that was supplied by user via command line option
|
|
124 This will be overridden in case of invalid combination
|
|
125 of core and data model options are supplied. */
|
|
126 static enum data_model_type data_model = DM_DEFAULT;
|
|
127
|
|
128 /* TARGETM Function Prototypes and forward declarations */
|
|
129 static void cr16_print_operand (FILE *, rtx, int);
|
|
130 static void cr16_print_operand_address (FILE *, machine_mode, rtx);
|
|
131
|
|
132 /* Stack layout and calling conventions. */
|
|
133 #undef TARGET_STRUCT_VALUE_RTX
|
|
134 #define TARGET_STRUCT_VALUE_RTX cr16_struct_value_rtx
|
|
135 #undef TARGET_RETURN_IN_MEMORY
|
|
136 #define TARGET_RETURN_IN_MEMORY cr16_return_in_memory
|
|
137
|
|
138 /* Target-specific uses of '__attribute__'. */
|
|
139 #undef TARGET_ATTRIBUTE_TABLE
|
|
140 #define TARGET_ATTRIBUTE_TABLE cr16_attribute_table
|
|
141 #undef TARGET_NARROW_VOLATILE_BITFIELD
|
|
142 #define TARGET_NARROW_VOLATILE_BITFIELD hook_bool_void_false
|
|
143
|
|
144 /* EH related. */
|
|
145 #undef TARGET_UNWIND_WORD_MODE
|
|
146 #define TARGET_UNWIND_WORD_MODE cr16_unwind_word_mode
|
|
147
|
|
148 /* Override Options. */
|
|
149 #undef TARGET_OPTION_OVERRIDE
|
|
150 #define TARGET_OPTION_OVERRIDE cr16_override_options
|
|
151
|
|
152 /* Conditional register usuage. */
|
|
153 #undef TARGET_CONDITIONAL_REGISTER_USAGE
|
|
154 #define TARGET_CONDITIONAL_REGISTER_USAGE cr16_conditional_register_usage
|
|
155
|
|
156 /* Controlling register spills. */
|
|
157 #undef TARGET_CLASS_LIKELY_SPILLED_P
|
|
158 #define TARGET_CLASS_LIKELY_SPILLED_P cr16_class_likely_spilled_p
|
|
159
|
|
160 /* Passing function arguments. */
|
|
161 #undef TARGET_FUNCTION_ARG
|
|
162 #define TARGET_FUNCTION_ARG cr16_function_arg
|
|
163 #undef TARGET_FUNCTION_ARG_ADVANCE
|
|
164 #define TARGET_FUNCTION_ARG_ADVANCE cr16_function_arg_advance
|
|
165 #undef TARGET_RETURN_POPS_ARGS
|
|
166 #define TARGET_RETURN_POPS_ARGS cr16_return_pops_args
|
|
167
|
|
168 /* Initialize the GCC target structure. */
|
|
169 #undef TARGET_FRAME_POINTER_REQUIRED
|
|
170 #define TARGET_FRAME_POINTER_REQUIRED cr16_frame_pointer_required
|
|
171 #undef TARGET_CAN_ELIMINATE
|
|
172 #define TARGET_CAN_ELIMINATE cr16_can_eliminate
|
|
173 #undef TARGET_LEGITIMIZE_ADDRESS
|
|
174 #define TARGET_LEGITIMIZE_ADDRESS cr16_legitimize_address
|
|
175 #undef TARGET_LEGITIMATE_CONSTANT_P
|
|
176 #define TARGET_LEGITIMATE_CONSTANT_P cr16_legitimate_constant_p
|
|
177 #undef TARGET_LEGITIMATE_ADDRESS_P
|
|
178 #define TARGET_LEGITIMATE_ADDRESS_P cr16_legitimate_address_p
|
|
179
|
|
180 #undef TARGET_LRA_P
|
|
181 #define TARGET_LRA_P hook_bool_void_false
|
|
182
|
|
183 /* Returning function value. */
|
|
184 #undef TARGET_FUNCTION_VALUE
|
|
185 #define TARGET_FUNCTION_VALUE cr16_function_value
|
|
186 #undef TARGET_LIBCALL_VALUE
|
|
187 #define TARGET_LIBCALL_VALUE cr16_libcall_value
|
|
188 #undef TARGET_FUNCTION_VALUE_REGNO_P
|
|
189 #define TARGET_FUNCTION_VALUE_REGNO_P cr16_function_value_regno_p
|
|
190
|
|
191 /* printing the values. */
|
|
192 #undef TARGET_PRINT_OPERAND
|
|
193 #define TARGET_PRINT_OPERAND cr16_print_operand
|
|
194 #undef TARGET_PRINT_OPERAND_ADDRESS
|
|
195 #define TARGET_PRINT_OPERAND_ADDRESS cr16_print_operand_address
|
|
196
|
|
197 /* Relative costs of operations. */
|
|
198 #undef TARGET_ADDRESS_COST
|
|
199 #define TARGET_ADDRESS_COST cr16_address_cost
|
|
200 #undef TARGET_REGISTER_MOVE_COST
|
|
201 #define TARGET_REGISTER_MOVE_COST cr16_register_move_cost
|
|
202 #undef TARGET_MEMORY_MOVE_COST
|
|
203 #define TARGET_MEMORY_MOVE_COST cr16_memory_move_cost
|
|
204
|
|
205 #undef TARGET_CONSTANT_ALIGNMENT
|
|
206 #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
|
|
207
|
|
208 /* Table of machine attributes. */
|
|
209 static const struct attribute_spec cr16_attribute_table[] = {
|
|
210 /* ISRs have special prologue and epilogue requirements. */
|
131
|
211 /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
|
|
212 affects_type_identity, handler, exclude }. */
|
|
213 {"interrupt", 0, 0, false, true, true, false, NULL, NULL},
|
|
214 {NULL, 0, 0, false, false, false, false, NULL, NULL}
|
111
|
215 };
|
|
216
|
|
217 /* TARGET_ASM_UNALIGNED_xx_OP generates .?byte directive
|
|
218 .?byte directive along with @c is not understood by assembler.
|
|
219 Therefore, make all TARGET_ASM_UNALIGNED_xx_OP same
|
|
220 as TARGET_ASM_ALIGNED_xx_OP. */
|
|
221 #undef TARGET_ASM_UNALIGNED_HI_OP
|
|
222 #define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP
|
|
223 #undef TARGET_ASM_UNALIGNED_SI_OP
|
|
224 #define TARGET_ASM_UNALIGNED_SI_OP TARGET_ASM_ALIGNED_SI_OP
|
|
225 #undef TARGET_ASM_UNALIGNED_DI_OP
|
|
226 #define TARGET_ASM_UNALIGNED_DI_OP TARGET_ASM_ALIGNED_DI_OP
|
|
227
|
|
228 #undef TARGET_HARD_REGNO_NREGS
|
|
229 #define TARGET_HARD_REGNO_NREGS cr16_hard_regno_nregs
|
|
230 #undef TARGET_HARD_REGNO_MODE_OK
|
|
231 #define TARGET_HARD_REGNO_MODE_OK cr16_hard_regno_mode_ok
|
|
232 #undef TARGET_MODES_TIEABLE_P
|
|
233 #define TARGET_MODES_TIEABLE_P cr16_modes_tieable_p
|
|
234
|
|
235 /* Target hook implementations. */
|
|
236
|
|
237 /* Implements hook TARGET_RETURN_IN_MEMORY. */
|
|
238 static bool
|
|
239 cr16_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
|
|
240 {
|
|
241 const HOST_WIDE_INT size = int_size_in_bytes (type);
|
|
242 return ((size == -1) || (size > 8));
|
|
243 }
|
|
244
|
|
245 /* Implement TARGET_CLASS_LIKELY_SPILLED_P. */
|
|
246 static bool
|
|
247 cr16_class_likely_spilled_p (reg_class_t rclass)
|
|
248 {
|
|
249 if ((rclass) == SHORT_REGS || (rclass) == DOUBLE_BASE_REGS
|
|
250 || (rclass) == LONG_REGS || (rclass) == GENERAL_REGS)
|
|
251 return true;
|
|
252
|
|
253 return false;
|
|
254 }
|
|
255
|
131
|
256 static poly_int64
|
|
257 cr16_return_pops_args (tree, tree, poly_int64)
|
111
|
258 {
|
|
259 return 0;
|
|
260 }
|
|
261
|
|
262 /* Returns true if data model selected via command line option
|
|
263 is same as function argument. */
|
|
264 bool
|
|
265 cr16_is_data_model (enum data_model_type model)
|
|
266 {
|
|
267 return (model == data_model);
|
|
268 }
|
|
269
|
|
270 /* Parse relevant options and override. */
|
|
271 static void
|
|
272 cr16_override_options (void)
|
|
273 {
|
|
274 /* Disable -fdelete-null-pointer-checks option for CR16 target.
|
|
275 Programs which rely on NULL pointer dereferences _not_ halting the
|
|
276 program may not work properly with this option. So disable this
|
|
277 option. */
|
|
278 flag_delete_null_pointer_checks = 0;
|
|
279
|
|
280 /* FIXME: To avoid spill_failure ICE during exception handling,
|
|
281 * disable cse_fllow_jumps. The spill error occurs when compiler
|
|
282 * can't find a suitable candidate in GENERAL_REGS class to reload
|
|
283 * a 32bit register.
|
|
284 * Need to find a better way of avoiding this situation. */
|
|
285 if (flag_exceptions)
|
|
286 flag_cse_follow_jumps = 0;
|
|
287
|
|
288 /* If -fpic option, data_model == DM_FAR. */
|
|
289 if (flag_pic == NEAR_PIC)
|
|
290 {
|
|
291 data_model = DM_FAR;
|
|
292 }
|
|
293
|
|
294 /* The only option we want to examine is data model option. */
|
|
295 if (cr16_data_model)
|
|
296 {
|
|
297 if (strcmp (cr16_data_model, "medium") == 0)
|
|
298 data_model = DM_DEFAULT;
|
|
299 else if (strcmp (cr16_data_model, "near") == 0)
|
|
300 data_model = DM_NEAR;
|
|
301 else if (strcmp (cr16_data_model, "far") == 0)
|
|
302 {
|
|
303 if (TARGET_CR16CP)
|
|
304 data_model = DM_FAR;
|
|
305 else
|
|
306 error ("data-model=far not valid for cr16c architecture");
|
|
307 }
|
|
308 else
|
|
309 error ("invalid data model option -mdata-model=%s", cr16_data_model);
|
|
310 }
|
|
311 else
|
|
312 data_model = DM_DEFAULT;
|
|
313 }
|
|
314
|
|
315 /* Implements the macro TARGET_CONDITIONAL_REGISTER_USAGE. */
|
|
316 static void
|
|
317 cr16_conditional_register_usage (void)
|
|
318 {
|
|
319 if (flag_pic)
|
|
320 {
|
|
321 fixed_regs[12] = call_used_regs[12] = 1;
|
|
322 }
|
|
323 }
|
|
324
|
|
325 /* Stack layout and calling conventions routines. */
|
|
326
|
|
327 /* Return nonzero if the current function being compiled is an interrupt
|
|
328 function as specified by the "interrupt" attribute. */
|
|
329 int
|
|
330 cr16_interrupt_function_p (void)
|
|
331 {
|
|
332 tree attributes;
|
|
333
|
|
334 attributes = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
|
|
335 return (lookup_attribute ("interrupt", attributes) != NULL_TREE);
|
|
336 }
|
|
337
|
|
338 /* Compute values for the array current_frame_info.save_regs and the variable
|
|
339 current_frame_info.reg_size. The index of current_frame_info.save_regs
|
|
340 is numbers of register, each will get 1 if we need to save it in the
|
|
341 current function, 0 if not. current_frame_info.reg_size is the total sum
|
|
342 of the registers being saved. */
|
|
343 static void
|
|
344 cr16_compute_save_regs (void)
|
|
345 {
|
|
346 unsigned int regno;
|
|
347
|
|
348 /* Initialize here so in case the function is no-return it will be -1. */
|
|
349 current_frame_info.last_reg_to_save = -1;
|
|
350
|
|
351 /* Initialize the number of bytes to be saved. */
|
|
352 current_frame_info.reg_size = 0;
|
|
353
|
|
354 /* No need to save any registers if the function never returns. */
|
|
355 if (FUNC_IS_NORETURN_P (current_function_decl) && !MUST_SAVE_REGS_P ())
|
|
356 return;
|
|
357
|
|
358 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
|
|
359 {
|
|
360 if (fixed_regs[regno])
|
|
361 {
|
|
362 current_frame_info.save_regs[regno] = 0;
|
|
363 continue;
|
|
364 }
|
|
365
|
|
366 /* If this reg is used and not call-used (except RA), save it. */
|
|
367 if (cr16_interrupt_function_p ())
|
|
368 {
|
|
369 if (!crtl->is_leaf && call_used_regs[regno])
|
|
370 /* This is a volatile reg in a non-leaf interrupt routine - save
|
|
371 it for the sake of its sons. */
|
|
372 current_frame_info.save_regs[regno] = 1;
|
|
373 else if (df_regs_ever_live_p (regno))
|
|
374 /* This reg is used - save it. */
|
|
375 current_frame_info.save_regs[regno] = 1;
|
|
376 else
|
|
377 /* This reg is not used, and is not a volatile - don't save. */
|
|
378 current_frame_info.save_regs[regno] = 0;
|
|
379 }
|
|
380 else
|
|
381 {
|
|
382 /* If this reg is used and not call-used (except RA), save it. */
|
|
383 if (df_regs_ever_live_p (regno)
|
|
384 && (!call_used_regs[regno] || regno == RETURN_ADDRESS_REGNUM))
|
|
385 current_frame_info.save_regs[regno] = 1;
|
|
386 else
|
|
387 current_frame_info.save_regs[regno] = 0;
|
|
388 }
|
|
389 }
|
|
390
|
|
391 /* Save registers so the exception handler can modify them. */
|
|
392 if (crtl->calls_eh_return)
|
|
393 {
|
|
394 unsigned int i;
|
|
395
|
|
396 for (i = 0;; ++i)
|
|
397 {
|
|
398 regno = EH_RETURN_DATA_REGNO (i);
|
|
399 if (INVALID_REGNUM == regno)
|
|
400 break;
|
|
401 current_frame_info.save_regs[regno] = 1;
|
|
402 }
|
|
403 }
|
|
404
|
|
405 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
|
|
406 if (current_frame_info.save_regs[regno] == 1)
|
|
407 {
|
|
408 current_frame_info.last_reg_to_save = regno;
|
|
409 if (regno >= CR16_FIRST_DWORD_REGISTER)
|
|
410 current_frame_info.reg_size += CR16_UNITS_PER_DWORD;
|
|
411 else
|
|
412 current_frame_info.reg_size += UNITS_PER_WORD;
|
|
413 }
|
|
414 }
|
|
415
|
|
416 /* Compute the size of the local area and the size to be adjusted by the
|
|
417 prologue and epilogue. */
|
|
418 static void
|
|
419 cr16_compute_frame (void)
|
|
420 {
|
|
421 /* For aligning the local variables. */
|
|
422 int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
|
|
423 int padding_locals;
|
|
424
|
|
425 /* Padding needed for each element of the frame. */
|
|
426 current_frame_info.var_size = get_frame_size ();
|
|
427
|
|
428 /* Align to the stack alignment. */
|
|
429 padding_locals = current_frame_info.var_size % stack_alignment;
|
|
430 if (padding_locals)
|
|
431 padding_locals = stack_alignment - padding_locals;
|
|
432
|
|
433 current_frame_info.var_size += padding_locals;
|
131
|
434 current_frame_info.total_size
|
|
435 = (current_frame_info.var_size
|
|
436 + (ACCUMULATE_OUTGOING_ARGS
|
|
437 ? (HOST_WIDE_INT) crtl->outgoing_args_size : 0));
|
111
|
438 }
|
|
439
|
|
440 /* Implements the macro INITIAL_ELIMINATION_OFFSET, return the OFFSET. */
|
|
441 int
|
|
442 cr16_initial_elimination_offset (int from, int to)
|
|
443 {
|
|
444 /* Compute this since we need to use current_frame_info.reg_size. */
|
|
445 cr16_compute_save_regs ();
|
|
446
|
|
447 /* Compute this since we need to use current_frame_info.var_size. */
|
|
448 cr16_compute_frame ();
|
|
449
|
|
450 if (((from) == FRAME_POINTER_REGNUM) && ((to) == STACK_POINTER_REGNUM))
|
131
|
451 return (ACCUMULATE_OUTGOING_ARGS
|
|
452 ? (HOST_WIDE_INT) crtl->outgoing_args_size : 0);
|
111
|
453 else if (((from) == ARG_POINTER_REGNUM) && ((to) == FRAME_POINTER_REGNUM))
|
|
454 return (current_frame_info.reg_size + current_frame_info.var_size);
|
|
455 else if (((from) == ARG_POINTER_REGNUM) && ((to) == STACK_POINTER_REGNUM))
|
|
456 return (current_frame_info.reg_size + current_frame_info.var_size
|
131
|
457 + (ACCUMULATE_OUTGOING_ARGS
|
|
458 ? (HOST_WIDE_INT) crtl->outgoing_args_size : 0));
|
111
|
459 else
|
|
460 gcc_unreachable ();
|
|
461 }
|
|
462
|
|
463 /* Register Usage. */
|
|
464
|
|
465 /* Return the class number of the smallest class containing reg number REGNO.
|
|
466 This could be a conditional expression or could index an array. */
|
|
467 enum reg_class
|
|
468 cr16_regno_reg_class (int regno)
|
|
469 {
|
|
470 if ((regno >= 0) && (regno < CR16_FIRST_DWORD_REGISTER))
|
|
471 return SHORT_REGS;
|
|
472
|
|
473 if ((regno >= CR16_FIRST_DWORD_REGISTER) && (regno < FIRST_PSEUDO_REGISTER))
|
|
474 return LONG_REGS;
|
|
475
|
|
476 return NO_REGS;
|
|
477 }
|
|
478
|
|
479 /* Implement TARGET_HARD_REGNO_NREGS. */
|
|
480
|
|
481 static unsigned int
|
|
482 cr16_hard_regno_nregs (unsigned int regno, machine_mode mode)
|
|
483 {
|
|
484 if (regno >= CR16_FIRST_DWORD_REGISTER)
|
|
485 return CEIL (GET_MODE_SIZE (mode), CR16_UNITS_PER_DWORD);
|
|
486 return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
|
|
487 }
|
|
488
|
|
489 /* Implement TARGET_HARD_REGNO_MODE_OK. On the CR16 architecture, all
|
|
490 registers can hold all modes, except that double precision floats
|
|
491 (and double ints) must fall on even-register boundaries. */
|
|
492
|
|
493 static bool
|
|
494 cr16_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
|
|
495 {
|
|
496 if ((GET_MODE_SIZE (mode) >= 4) && (regno == 11))
|
|
497 return false;
|
|
498
|
|
499 if (mode == DImode || mode == DFmode)
|
|
500 {
|
|
501 if ((regno > 8) || (regno & 1))
|
|
502 return false;
|
|
503 return true;
|
|
504 }
|
|
505
|
|
506 if ((TARGET_INT32)
|
|
507 && ((regno >= 12) && (GET_MODE_SIZE (mode) < 4 )))
|
|
508 return false;
|
|
509
|
|
510 /* CC can only hold CCmode values. */
|
|
511 if (GET_MODE_CLASS (mode) == MODE_CC)
|
|
512 return false;
|
|
513 return true;
|
|
514 }
|
|
515
|
|
516 /* Implement TARGET_MODES_TIEABLE_P. */
|
|
517 static bool
|
|
518 cr16_modes_tieable_p (machine_mode mode1, machine_mode mode2)
|
|
519 {
|
|
520 return GET_MODE_CLASS (mode1) == GET_MODE_CLASS (mode2);
|
|
521 }
|
|
522
|
|
523 /* Returns register number for function return value.*/
|
|
524 static inline unsigned int
|
|
525 cr16_ret_register (void)
|
|
526 {
|
|
527 return 0;
|
|
528 }
|
|
529
|
|
530 /* Implements hook TARGET_STRUCT_VALUE_RTX. */
|
|
531 static rtx
|
|
532 cr16_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
|
|
533 int incoming ATTRIBUTE_UNUSED)
|
|
534 {
|
|
535 return gen_rtx_REG (Pmode, cr16_ret_register ());
|
|
536 }
|
|
537
|
|
538 /* Returning function value. */
|
|
539
|
|
540 /* Worker function for TARGET_FUNCTION_VALUE_REGNO_P. */
|
|
541 static bool
|
|
542 cr16_function_value_regno_p (const unsigned int regno)
|
|
543 {
|
|
544 return (regno == cr16_ret_register ());
|
|
545 }
|
|
546
|
|
547 /* Create an RTX representing the place where a
|
|
548 library function returns a value of mode MODE. */
|
|
549 static rtx
|
|
550 cr16_libcall_value (machine_mode mode,
|
|
551 const_rtx func ATTRIBUTE_UNUSED)
|
|
552 {
|
|
553 return gen_rtx_REG (mode, cr16_ret_register ());
|
|
554 }
|
|
555
|
|
556 /* Create an RTX representing the place where a
|
|
557 function returns a value of data type VALTYPE. */
|
|
558 static rtx
|
|
559 cr16_function_value (const_tree type,
|
|
560 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
|
|
561 bool outgoing ATTRIBUTE_UNUSED)
|
|
562 {
|
|
563 return gen_rtx_REG (TYPE_MODE (type), cr16_ret_register ());
|
|
564 }
|
|
565
|
|
566 /* Passing function arguments. */
|
|
567
|
|
568 /* If enough param regs are available for passing the param of type TYPE return
|
|
569 the number of registers needed else 0. */
|
|
570 static int
|
|
571 enough_regs_for_param (CUMULATIVE_ARGS * cum, const_tree type,
|
|
572 machine_mode mode)
|
|
573 {
|
|
574 int type_size;
|
|
575 int remaining_size;
|
|
576
|
|
577 if (mode != BLKmode)
|
|
578 type_size = GET_MODE_BITSIZE (mode);
|
|
579 else
|
|
580 type_size = int_size_in_bytes (type) * BITS_PER_UNIT;
|
|
581
|
|
582 remaining_size = BITS_PER_WORD * (MAX_REG_FOR_PASSING_ARGS
|
|
583 - (MIN_REG_FOR_PASSING_ARGS + cum->ints) +
|
|
584 1);
|
|
585
|
|
586 /* Any variable which is too big to pass in two registers, will pass on
|
|
587 stack. */
|
|
588 if ((remaining_size >= type_size) && (type_size <= 2 * BITS_PER_WORD))
|
|
589 return (type_size + BITS_PER_WORD - 1) / BITS_PER_WORD;
|
|
590
|
|
591 return 0;
|
|
592 }
|
|
593
|
|
594 /* Implements the macro FUNCTION_ARG defined in cr16.h. */
|
|
595 static rtx
|
|
596 cr16_function_arg (cumulative_args_t cum_v, machine_mode mode,
|
|
597 const_tree type, bool named ATTRIBUTE_UNUSED)
|
|
598 {
|
|
599 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
|
|
600 cum->last_parm_in_reg = 0;
|
|
601
|
|
602 /* function_arg () is called with this type just after all the args have
|
|
603 had their registers assigned. The rtx that function_arg returns from
|
|
604 this type is supposed to pass to 'gen_call' but currently it is not
|
|
605 implemented. */
|
|
606 if (type == void_type_node)
|
|
607 return NULL_RTX;
|
|
608
|
|
609 if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0))
|
|
610 return NULL_RTX;
|
|
611
|
|
612 if (mode == BLKmode)
|
|
613 {
|
|
614 /* Enable structures that need padding bytes at the end to pass to a
|
|
615 function in registers. */
|
|
616 if (enough_regs_for_param (cum, type, mode) != 0)
|
|
617 {
|
|
618 cum->last_parm_in_reg = 1;
|
|
619 return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints);
|
|
620 }
|
|
621 }
|
|
622
|
|
623 if ((MIN_REG_FOR_PASSING_ARGS + cum->ints) > MAX_REG_FOR_PASSING_ARGS)
|
|
624 return NULL_RTX;
|
|
625 else
|
|
626 {
|
|
627 if (enough_regs_for_param (cum, type, mode) != 0)
|
|
628 {
|
|
629 cum->last_parm_in_reg = 1;
|
|
630 return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints);
|
|
631 }
|
|
632 }
|
|
633
|
|
634 return NULL_RTX;
|
|
635 }
|
|
636
|
|
637 /* Implements the macro INIT_CUMULATIVE_ARGS defined in cr16.h. */
|
|
638 void
|
|
639 cr16_init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
|
|
640 rtx libfunc ATTRIBUTE_UNUSED)
|
|
641 {
|
|
642 tree param, next_param;
|
|
643
|
|
644 cum->ints = 0;
|
|
645
|
|
646 /* Determine if this function has variable arguments. This is indicated by
|
|
647 the last argument being 'void_type_mode' if there are no variable
|
|
648 arguments. Change here for a different vararg. */
|
|
649 for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
|
|
650 param != NULL_TREE; param = next_param)
|
|
651 {
|
|
652 next_param = TREE_CHAIN (param);
|
|
653 if ((next_param == NULL_TREE) && (TREE_VALUE (param) != void_type_node))
|
|
654 {
|
|
655 cum->ints = -1;
|
|
656 return;
|
|
657 }
|
|
658 }
|
|
659 }
|
|
660
|
|
661 /* Implements the macro FUNCTION_ARG_ADVANCE defined in cr16.h. */
|
|
662 static void
|
|
663 cr16_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
|
|
664 const_tree type, bool named ATTRIBUTE_UNUSED)
|
|
665 {
|
|
666 CUMULATIVE_ARGS * cum = get_cumulative_args (cum_v);
|
|
667
|
|
668 /* l holds the number of registers required. */
|
|
669 int l = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
|
|
670
|
|
671 /* If the parameter isn't passed on a register don't advance cum. */
|
|
672 if (!cum->last_parm_in_reg)
|
|
673 return;
|
|
674
|
|
675 if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0))
|
|
676 return;
|
|
677
|
|
678 if ((mode == SImode) || (mode == HImode)
|
|
679 || (mode == QImode) || (mode == DImode))
|
|
680 {
|
|
681 if (l <= 1)
|
|
682 cum->ints += 1;
|
|
683 else
|
|
684 cum->ints += l;
|
|
685 }
|
|
686 else if ((mode == SFmode) || (mode == DFmode))
|
|
687 cum->ints += l;
|
|
688 else if ((mode) == BLKmode)
|
|
689 {
|
|
690 if ((l = enough_regs_for_param (cum, type, mode)) != 0)
|
|
691 cum->ints += l;
|
|
692 }
|
|
693 return;
|
|
694 }
|
|
695
|
|
696 /* Implements the macro FUNCTION_ARG_REGNO_P defined in cr16.h.
|
|
697 Return nonzero if N is a register used for passing parameters. */
|
|
698 int
|
|
699 cr16_function_arg_regno_p (int n)
|
|
700 {
|
|
701 return ((n <= MAX_REG_FOR_PASSING_ARGS) && (n >= MIN_REG_FOR_PASSING_ARGS));
|
|
702 }
|
|
703
|
|
704 /* Addressing modes.
|
|
705 Following set of function implement the macro GO_IF_LEGITIMATE_ADDRESS
|
|
706 defined in cr16.h. */
|
|
707
|
|
708 /* Helper function to check if is a valid base register that can
|
|
709 hold address. */
|
|
710 static int
|
|
711 cr16_addr_reg_p (rtx addr_reg)
|
|
712 {
|
|
713 rtx reg;
|
|
714
|
|
715 if (REG_P (addr_reg))
|
|
716 reg = addr_reg;
|
|
717 else if ((GET_CODE (addr_reg) == SUBREG)
|
|
718 && REG_P (SUBREG_REG (addr_reg))
|
|
719 && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (addr_reg)))
|
|
720 <= UNITS_PER_WORD))
|
|
721 reg = SUBREG_REG (addr_reg);
|
|
722 else
|
|
723 return FALSE;
|
|
724
|
|
725 if (GET_MODE (reg) != Pmode)
|
|
726 return FALSE;
|
|
727
|
|
728 return TRUE;
|
|
729 }
|
|
730
|
|
731 /* Helper functions: Created specifically for decomposing operand of CONST
|
|
732 Recursively look into expression x for code or data symbol.
|
|
733 The function expects the expression to contain combination of
|
|
734 SYMBOL_REF, CONST_INT, (PLUS or MINUS)
|
|
735 LABEL_REF, CONST_INT, (PLUS or MINUS)
|
|
736 SYMBOL_REF
|
|
737 LABEL_REF
|
|
738 All other combinations will result in code = -1 and data = ILLEGAL_DM
|
|
739 code data
|
|
740 -1 ILLEGAL_DM The expression did not contain SYMBOL_REF or LABEL_REF
|
|
741 0 DM_FAR SYMBOL_REF was found and it was far data reference.
|
|
742 0 DM_DEFAULT SYMBOL_REF was found and it was medium data reference.
|
|
743 1 ILLEGAL_DM LABEL_REF was found.
|
|
744 2 ILLEGAL_DM SYMBOL_REF was found and it was function reference. */
|
|
745 void
|
|
746 cr16_decompose_const (rtx x, int *code, enum data_model_type *data,
|
|
747 bool treat_as_const)
|
|
748 {
|
|
749 *code = -1;
|
|
750 *data = ILLEGAL_DM;
|
|
751 switch (GET_CODE (x))
|
|
752 {
|
|
753 case SYMBOL_REF:
|
|
754 *code = SYMBOL_REF_FUNCTION_P (x) ? 2 : 0;
|
|
755 /* 2 indicates func sym. */
|
|
756 if (*code == 0)
|
|
757 {
|
|
758 if (CR16_TARGET_DATA_NEAR)
|
|
759 *data = DM_DEFAULT;
|
|
760 else if (CR16_TARGET_DATA_MEDIUM)
|
|
761 *data = DM_FAR;
|
|
762 else if (CR16_TARGET_DATA_FAR)
|
|
763 {
|
|
764 if (treat_as_const)
|
|
765 /* This will be used only for printing
|
|
766 the qualifier. This call is (may be)
|
|
767 made by cr16_print_operand_address. */
|
|
768 *data = DM_FAR;
|
|
769 else
|
|
770 /* This call is (may be) made by
|
|
771 cr16_legitimate_address_p. */
|
|
772 *data = ILLEGAL_DM;
|
|
773 }
|
|
774 }
|
|
775 return;
|
|
776
|
|
777 case LABEL_REF:
|
|
778 /* 1 - indicates non-function symbol. */
|
|
779 *code = 1;
|
|
780 return;
|
|
781
|
|
782 case PLUS:
|
|
783 case MINUS:
|
|
784 /* Look into the tree nodes. */
|
|
785 if (GET_CODE (XEXP (x, 0)) == CONST_INT)
|
|
786 cr16_decompose_const (XEXP (x, 1), code, data, treat_as_const);
|
|
787 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
|
|
788 cr16_decompose_const (XEXP (x, 0), code, data, treat_as_const);
|
|
789 return;
|
|
790 default:
|
|
791 return;
|
|
792 }
|
|
793 }
|
|
794
|
|
795 /* Decompose Address
|
|
796 This function decomposes the address returns the type of address
|
|
797 as defined in enum cr16_addrtype. It also fills the parameter *out.
|
|
798 The decomposed address can be used for two purposes. One to
|
|
799 check if the address is valid and second to print the address
|
|
800 operand.
|
|
801
|
|
802 Following tables list valid address supported in CR16C/C+ architectures.
|
|
803 Legend:
|
|
804 aN : Absoulte address N-bit address
|
|
805 R : One 16-bit register
|
|
806 RP : Consecutive two 16-bit registers or one 32-bit register
|
|
807 I : One 32-bit register
|
|
808 dispN : Signed displacement of N-bits
|
|
809
|
|
810 ----Code addresses----
|
|
811 Branch operands:
|
|
812 disp9 : CR16_ABSOLUTE (disp)
|
|
813 disp17 : CR16_ABSOLUTE (disp)
|
|
814 disp25 : CR16_ABSOLUTE (disp)
|
|
815 RP + disp25 : CR16_REGP_REL (base, disp)
|
|
816
|
|
817 Jump operands:
|
|
818 RP : CR16_REGP_REL (base, disp=0)
|
|
819 a24 : CR16_ABSOLUTE (disp)
|
|
820
|
|
821 ----Data addresses----
|
|
822 a20 : CR16_ABSOLUTE (disp) near (1M)
|
|
823 a24 : CR16_ABSOLUTE (disp) medium (16M)
|
|
824 R + d20 : CR16_REG_REL (base, disp) near (1M+64K)
|
|
825 RP + d4 : CR16_REGP_REL (base, disp) far (4G)
|
|
826 RP + d16 : CR16_REGP_REL (base, disp) far (4G)
|
|
827 RP + d20 : CR16_REGP_REL (base, disp) far (4G)
|
|
828 I : *** Valid but port does not support this
|
|
829 I + a20 : *** Valid but port does not support this
|
|
830 I + RP + d14: CR16_INDEX_REGP_REL (base, index, disp) far (4G)
|
|
831 I + RP + d20: CR16_INDEX_REGP_REL (base, index, disp) far (4G)
|
|
832
|
|
833 Decomposing Data model in case of absolute address.
|
|
834
|
|
835 Target Option Address type Resultant Data ref type
|
|
836 ---------------------- ------------ -----------------------
|
|
837 CR16_TARGET_MODEL_NEAR ABS20 DM_DEFAULT
|
|
838 CR16_TARGET_MODEL_NEAR IMM20 DM_DEFAULT
|
|
839 CR16_TARGET_MODEL_NEAR ABS24 Invalid
|
|
840 CR16_TARGET_MODEL_NEAR IMM32 Invalid
|
|
841
|
|
842 CR16_TARGET_MODEL_MEDIUM ABS20 DM_DEFAULT
|
|
843 CR16_TARGET_MODEL_MEDIUM IMM20 DM_DEFAULT
|
|
844 CR16_TARGET_MODEL_MEDIUM ABS24 DM_FAR
|
|
845 CR16_TARGET_MODEL_MEDIUM IMM32 Invalid
|
|
846
|
|
847 CR16_TARGET_MODEL_FAR ABS20 DM_DEFAULT
|
|
848 CR16_TARGET_MODEL_FAR IMM20 DM_DEFAULT
|
|
849 CR16_TARGET_MODEL_FAR ABS24 DM_FAR
|
|
850 CR16_TARGET_MODEL_FAR IMM32 DM_FAR. */
|
|
851 enum cr16_addrtype
|
|
852 cr16_decompose_address (rtx addr, struct cr16_address *out,
|
|
853 bool debug_print, bool treat_as_const)
|
|
854 {
|
|
855 rtx base = NULL_RTX, disp = NULL_RTX, index = NULL_RTX;
|
|
856 enum data_model_type data = ILLEGAL_DM;
|
|
857 int code = -1;
|
|
858 enum cr16_addrtype retval = CR16_INVALID;
|
|
859
|
|
860 switch (GET_CODE (addr))
|
|
861 {
|
|
862 case CONST_INT:
|
|
863 /* Absolute address (known at compile time). */
|
|
864 code = 0;
|
|
865 if (debug_print)
|
|
866 fprintf (stderr, "\ncode:%d", code);
|
|
867 disp = addr;
|
|
868
|
|
869 if (debug_print)
|
|
870 {
|
|
871 fprintf (stderr, "\ndisp:");
|
|
872 debug_rtx (disp);
|
|
873 }
|
|
874
|
|
875 if (UNSIGNED_INT_FITS_N_BITS (INTVAL (disp), 20))
|
|
876 {
|
|
877 data = DM_DEFAULT;
|
|
878 if (debug_print)
|
|
879 fprintf (stderr, "\ndata:%d", data);
|
|
880 retval = CR16_ABSOLUTE;
|
|
881 }
|
|
882 else if (UNSIGNED_INT_FITS_N_BITS (INTVAL (disp), 24))
|
|
883 {
|
|
884 if (!CR16_TARGET_DATA_NEAR)
|
|
885 {
|
|
886 data = DM_FAR;
|
|
887 if (debug_print)
|
|
888 fprintf (stderr, "\ndata:%d", data);
|
|
889 retval = CR16_ABSOLUTE;
|
|
890 }
|
|
891 else
|
|
892 return CR16_INVALID; /* ABS24 is not support in NEAR model. */
|
|
893 }
|
|
894 else
|
|
895 return CR16_INVALID;
|
|
896 break;
|
|
897
|
|
898 case CONST:
|
|
899 /* A CONST is an expression of PLUS or MINUS with
|
|
900 CONST_INT, SYMBOL_REF or LABEL_REF. This is the
|
|
901 result of assembly-time arithmetic computation. */
|
|
902 retval = CR16_ABSOLUTE;
|
|
903 disp = addr;
|
|
904 /* Call the helper function to check the validity. */
|
|
905 cr16_decompose_const (XEXP (addr, 0), &code, &data, treat_as_const);
|
|
906 if ((code == 0) && (data == ILLEGAL_DM))
|
|
907 /* CONST is not valid code or data address. */
|
|
908 return CR16_INVALID;
|
|
909 if (debug_print)
|
|
910 {
|
|
911 fprintf (stderr, "\ndisp:");
|
|
912 debug_rtx (disp);
|
|
913 fprintf (stderr, "\ncode:%d", code);
|
|
914 fprintf (stderr, "\ndata:%d", data);
|
|
915 }
|
|
916 break;
|
|
917
|
|
918 case LABEL_REF:
|
|
919 retval = CR16_ABSOLUTE;
|
|
920 disp = addr;
|
|
921 /* 1 - indicates non-function symbol. */
|
|
922 code = 1;
|
|
923 if (debug_print)
|
|
924 {
|
|
925 fprintf (stderr, "\ndisp:");
|
|
926 debug_rtx (disp);
|
|
927 fprintf (stderr, "\ncode:%d", code);
|
|
928 }
|
|
929 break;
|
|
930
|
|
931 case SYMBOL_REF:
|
|
932 /* Absolute address (known at link time). */
|
|
933 retval = CR16_ABSOLUTE;
|
|
934 disp = addr;
|
|
935 /* This is a code address if symbol_ref is a function. */
|
|
936 /* 2 indicates func sym. */
|
|
937 code = SYMBOL_REF_FUNCTION_P (addr) ? 2 : 0;
|
|
938 if (debug_print)
|
|
939 {
|
|
940 fprintf (stderr, "\ndisp:");
|
|
941 debug_rtx (disp);
|
|
942 fprintf (stderr, "\ncode:%d", code);
|
|
943 }
|
|
944 /* If not function ref then check if valid data ref. */
|
|
945 if (code == 0)
|
|
946 {
|
|
947 if (CR16_TARGET_DATA_NEAR)
|
|
948 data = DM_DEFAULT;
|
|
949 else if (CR16_TARGET_DATA_MEDIUM)
|
|
950 data = DM_FAR;
|
|
951 else if (CR16_TARGET_DATA_FAR)
|
|
952 {
|
|
953 if (treat_as_const)
|
|
954 /* This will be used only for printing the
|
|
955 qualifier. This call is (may be) made
|
|
956 by cr16_print_operand_address. */
|
|
957 data = DM_FAR;
|
|
958 else
|
|
959 /* This call is (may be) made by
|
|
960 cr16_legitimate_address_p. */
|
|
961 return CR16_INVALID;
|
|
962 }
|
|
963 else
|
|
964 data = DM_DEFAULT;
|
|
965 }
|
|
966 if (debug_print)
|
|
967 fprintf (stderr, "\ndata:%d", data);
|
|
968 break;
|
|
969
|
|
970 case REG:
|
|
971 case SUBREG:
|
|
972 /* Register relative address. */
|
|
973 /* Assume REG fits in a single register. */
|
|
974 retval = CR16_REG_REL;
|
|
975 if (GET_MODE_BITSIZE (GET_MODE (addr)) > BITS_PER_WORD)
|
|
976 if (!LONG_REG_P (REGNO (addr)))
|
|
977 /* REG will result in reg pair. */
|
|
978 retval = CR16_REGP_REL;
|
|
979 base = addr;
|
|
980 if (debug_print)
|
|
981 {
|
|
982 fprintf (stderr, "\nbase:");
|
|
983 debug_rtx (base);
|
|
984 }
|
|
985 break;
|
|
986
|
|
987 case PLUS:
|
|
988 switch (GET_CODE (XEXP (addr, 0)))
|
|
989 {
|
|
990 case REG:
|
|
991 case SUBREG:
|
|
992 /* REG + DISP20. */
|
|
993 /* All Reg relative addresses having a displacement needs
|
|
994 to fit in 20-bits. */
|
|
995 disp = XEXP (addr, 1);
|
|
996 if (debug_print)
|
|
997 {
|
|
998 fprintf (stderr, "\ndisp:");
|
|
999 debug_rtx (disp);
|
|
1000 }
|
|
1001 switch (GET_CODE (XEXP (addr, 1)))
|
|
1002 {
|
|
1003 case CONST_INT:
|
|
1004 /* Shall fit in 20-bits. */
|
|
1005 if (!UNSIGNED_INT_FITS_N_BITS (INTVAL (disp), 20))
|
|
1006 return CR16_INVALID;
|
|
1007 code = 0;
|
|
1008 if (debug_print)
|
|
1009 fprintf (stderr, "\ncode:%d", code);
|
|
1010 break;
|
|
1011
|
|
1012 case UNSPEC:
|
|
1013 switch (XINT (XEXP (addr, 1), 1))
|
|
1014 {
|
|
1015 case UNSPEC_LIBRARY_OFFSET:
|
|
1016 default:
|
|
1017 gcc_unreachable ();
|
|
1018 }
|
|
1019 break;
|
|
1020
|
|
1021 case LABEL_REF:
|
|
1022 case SYMBOL_REF:
|
|
1023 case CONST:
|
|
1024 /* This is also a valid expression for address.
|
|
1025 However, we cannot ascertain if the resultant
|
|
1026 displacement will be valid 20-bit value. Therefore,
|
|
1027 lets not allow such an expression for now. This will
|
|
1028 be updated when we find a way to validate this
|
|
1029 expression as legitimate address.
|
|
1030 Till then fall through CR16_INVALID. */
|
|
1031 default:
|
|
1032 return CR16_INVALID;
|
|
1033 }
|
|
1034
|
|
1035 /* Now check if REG can fit into single or pair regs. */
|
|
1036 retval = CR16_REG_REL;
|
|
1037 base = XEXP (addr, 0);
|
|
1038 if (debug_print)
|
|
1039 {
|
|
1040 fprintf (stderr, "\nbase:");
|
|
1041 debug_rtx (base);
|
|
1042 }
|
|
1043 if (GET_MODE_BITSIZE (GET_MODE ((XEXP (addr, 0)))) > BITS_PER_WORD)
|
|
1044 {
|
|
1045 if (!LONG_REG_P (REGNO ((XEXP (addr, 0)))))
|
|
1046 /* REG will result in reg pair. */
|
|
1047 retval = CR16_REGP_REL;
|
|
1048 }
|
|
1049 break;
|
|
1050
|
|
1051 case PLUS:
|
|
1052 /* Valid expr:
|
|
1053 plus
|
|
1054 /\
|
|
1055 / \
|
|
1056 plus idx
|
|
1057 /\
|
|
1058 / \
|
|
1059 reg const_int
|
|
1060
|
|
1061 Check if the operand 1 is valid index register. */
|
|
1062 data = ILLEGAL_DM;
|
|
1063 if (debug_print)
|
|
1064 fprintf (stderr, "\ndata:%d", data);
|
|
1065 switch (GET_CODE (XEXP (addr, 1)))
|
|
1066 {
|
|
1067 case REG:
|
|
1068 case SUBREG:
|
|
1069 if (!REG_OK_FOR_INDEX_P (XEXP (addr, 1)))
|
|
1070 return CR16_INVALID;
|
|
1071 /* OK. REG is a valid index register. */
|
|
1072 index = XEXP (addr, 1);
|
|
1073 if (debug_print)
|
|
1074 {
|
|
1075 fprintf (stderr, "\nindex:");
|
|
1076 debug_rtx (index);
|
|
1077 }
|
|
1078 break;
|
|
1079 default:
|
|
1080 return CR16_INVALID;
|
|
1081 }
|
|
1082 /* Check if operand 0 of operand 0 is REGP. */
|
|
1083 switch (GET_CODE (XEXP (XEXP (addr, 0), 0)))
|
|
1084 {
|
|
1085 case REG:
|
|
1086 case SUBREG:
|
|
1087 /* Now check if REG is a REGP and not in LONG regs. */
|
|
1088 if (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (addr, 0), 0)))
|
|
1089 > BITS_PER_WORD)
|
|
1090 {
|
|
1091 if (REGNO (XEXP (XEXP (addr, 0), 0))
|
|
1092 >= CR16_FIRST_DWORD_REGISTER)
|
|
1093 return CR16_INVALID;
|
|
1094 base = XEXP (XEXP (addr, 0), 0);
|
|
1095 if (debug_print)
|
|
1096 {
|
|
1097 fprintf (stderr, "\nbase:");
|
|
1098 debug_rtx (base);
|
|
1099 }
|
|
1100 }
|
|
1101 else
|
|
1102 return CR16_INVALID;
|
|
1103 break;
|
|
1104 default:
|
|
1105 return CR16_INVALID;
|
|
1106 }
|
|
1107 /* Now check if the operand 1 of operand 0 is const_int. */
|
|
1108 if (GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
|
|
1109 {
|
|
1110 disp = XEXP (XEXP (addr, 0), 1);
|
|
1111 if (debug_print)
|
|
1112 {
|
|
1113 fprintf (stderr, "\ndisp:");
|
|
1114 debug_rtx (disp);
|
|
1115 }
|
|
1116 if (!UNSIGNED_INT_FITS_N_BITS (INTVAL (disp), 20))
|
|
1117 return CR16_INVALID;
|
|
1118 }
|
|
1119 else
|
|
1120 return CR16_INVALID;
|
|
1121 retval = CR16_INDEX_REGP_REL;
|
|
1122 break;
|
|
1123 default:
|
|
1124 return CR16_INVALID;
|
|
1125 }
|
|
1126 break;
|
|
1127
|
|
1128 default:
|
|
1129 return CR16_INVALID;
|
|
1130 }
|
|
1131
|
|
1132 /* Check if the base and index registers are valid. */
|
|
1133 if (base && !(cr16_addr_reg_p (base)))
|
|
1134 return CR16_INVALID;
|
|
1135 if (base && !(CR16_REG_OK_FOR_BASE_P (base)))
|
|
1136 return CR16_INVALID;
|
|
1137 if (index && !(REG_OK_FOR_INDEX_P (index)))
|
|
1138 return CR16_INVALID;
|
|
1139
|
|
1140 /* Write the decomposition to out parameter. */
|
|
1141 out->base = base;
|
|
1142 out->disp = disp;
|
|
1143 out->index = index;
|
|
1144 out->data = data;
|
|
1145 out->code = code;
|
|
1146
|
|
1147 return retval;
|
|
1148 }
|
|
1149
|
|
1150 /* Return non-zero value if 'x' is legitimate PIC operand
|
|
1151 when generating PIC code. */
|
|
1152 int
|
|
1153 legitimate_pic_operand_p (rtx x)
|
|
1154 {
|
|
1155 switch (GET_CODE (x))
|
|
1156 {
|
|
1157 case SYMBOL_REF:
|
|
1158 return 0;
|
|
1159 case LABEL_REF:
|
|
1160 return 0;
|
|
1161 case CONST:
|
|
1162 /* REVISIT: Use something like symbol_referenced_p. */
|
|
1163 if (GET_CODE (XEXP (x, 0)) == PLUS
|
|
1164 && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
|
|
1165 || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
|
|
1166 && (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
|
|
1167 return 0;
|
|
1168 break;
|
|
1169 case MEM:
|
|
1170 return legitimate_pic_operand_p (XEXP (x, 0));
|
|
1171 default:
|
|
1172 break;
|
|
1173 }
|
|
1174 return 1;
|
|
1175 }
|
|
1176
|
|
1177 /* Convert a non-PIC address in `orig' to a PIC address in `reg'.
|
|
1178
|
|
1179 Input Output (-f pic) Output (-f PIC)
|
|
1180 orig reg
|
|
1181
|
|
1182 C1 symbol symbol@BRO (r12) symbol@GOT (r12)
|
|
1183
|
|
1184 C2 symbol + offset symbol+offset@BRO (r12) symbol+offset@GOT (r12)
|
|
1185
|
|
1186 NOTE: @BRO is added using unspec:BRO
|
|
1187 NOTE: @GOT is added using unspec:GOT. */
|
|
1188 rtx
|
|
1189 legitimize_pic_address (rtx orig, machine_mode mode ATTRIBUTE_UNUSED,
|
|
1190 rtx reg)
|
|
1191 {
|
|
1192 /* First handle a simple SYMBOL_REF or LABEL_REF. */
|
|
1193 if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF)
|
|
1194 {
|
|
1195 if (reg == 0)
|
|
1196 reg = gen_reg_rtx (Pmode);
|
|
1197
|
|
1198 if (flag_pic == NEAR_PIC)
|
|
1199 {
|
|
1200 /* Unspec to handle -fpic option. */
|
|
1201 emit_insn (gen_unspec_bro_addr (reg, orig));
|
|
1202 emit_insn (gen_addsi3 (reg, reg, pic_offset_table_rtx));
|
|
1203 }
|
|
1204 else if (flag_pic == FAR_PIC)
|
|
1205 {
|
|
1206 /* Unspec to handle -fPIC option. */
|
|
1207 emit_insn (gen_unspec_got_addr (reg, orig));
|
|
1208 }
|
|
1209 return reg;
|
|
1210 }
|
|
1211 else if (GET_CODE (orig) == CONST)
|
|
1212 {
|
|
1213 /* To handle (symbol + offset). */
|
|
1214 rtx base, offset;
|
|
1215
|
|
1216 if (GET_CODE (XEXP (orig, 0)) == PLUS
|
|
1217 && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
|
|
1218 return orig;
|
|
1219
|
|
1220 if (reg == 0)
|
|
1221 {
|
|
1222 gcc_assert (can_create_pseudo_p ());
|
|
1223 reg = gen_reg_rtx (Pmode);
|
|
1224 }
|
|
1225
|
|
1226 gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
|
|
1227
|
|
1228 base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
|
|
1229 offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
|
|
1230 base == reg ? 0 : reg);
|
|
1231
|
|
1232 /* REVISIT: Optimize for const-offsets. */
|
|
1233 emit_insn (gen_addsi3 (reg, base, offset));
|
|
1234
|
|
1235 return reg;
|
|
1236 }
|
|
1237 return orig;
|
|
1238 }
|
|
1239
|
|
1240 /* Implementation of TARGET_LEGITIMATE_ADDRESS_P. */
|
|
1241 static bool
|
|
1242 cr16_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
|
|
1243 rtx addr, bool strict)
|
|
1244 {
|
|
1245 enum cr16_addrtype addrtype;
|
|
1246 struct cr16_address address;
|
|
1247
|
|
1248 if (TARGET_DEBUG_ADDR)
|
|
1249 {
|
|
1250 fprintf (stderr,
|
|
1251 "\n======\nTARGET_LEGITIMATE_ADDRESS_P, mode = %s, strict = %d",
|
|
1252 GET_MODE_NAME (mode), strict);
|
|
1253 debug_rtx (addr);
|
|
1254 }
|
|
1255 addrtype = cr16_decompose_address (addr, &address,
|
|
1256 (TARGET_DEBUG_ADDR ? 1 : 0), FALSE);
|
|
1257
|
|
1258 if (TARGET_DEBUG_ADDR)
|
|
1259 {
|
|
1260 const char *typestr;
|
|
1261
|
|
1262 switch (addrtype)
|
|
1263 {
|
|
1264 case CR16_INVALID:
|
|
1265 typestr = "invalid";
|
|
1266 break;
|
|
1267 case CR16_ABSOLUTE:
|
|
1268 typestr = "absolute";
|
|
1269 break;
|
|
1270 case CR16_REG_REL:
|
|
1271 typestr = "register relative";
|
|
1272 break;
|
|
1273 case CR16_REGP_REL:
|
|
1274 typestr = "register pair relative";
|
|
1275 break;
|
|
1276 case CR16_INDEX_REGP_REL:
|
|
1277 typestr = "index + register pair relative";
|
|
1278 break;
|
|
1279 default:
|
|
1280 gcc_unreachable ();
|
|
1281 }
|
|
1282 fprintf (stderr, "\ncr16 address type: %s\n", typestr);
|
|
1283 }
|
|
1284
|
|
1285 if (addrtype == CR16_INVALID)
|
|
1286 return FALSE;
|
|
1287
|
|
1288 if (strict)
|
|
1289 {
|
|
1290 if (address.base
|
|
1291 && !REGNO_MODE_OK_FOR_BASE_P (REGNO (address.base), mode))
|
|
1292 {
|
|
1293 if (TARGET_DEBUG_ADDR)
|
|
1294 fprintf (stderr, "base register not strict\n");
|
|
1295 return FALSE;
|
|
1296 }
|
|
1297 if (address.index && !REGNO_OK_FOR_INDEX_P (REGNO (address.index)))
|
|
1298 {
|
|
1299 if (TARGET_DEBUG_ADDR)
|
|
1300 fprintf (stderr, "index register not strict\n");
|
|
1301 return FALSE;
|
|
1302 }
|
|
1303 }
|
|
1304
|
|
1305 /* Return true if addressing mode is register relative. */
|
|
1306 if (flag_pic)
|
|
1307 {
|
|
1308 if (addrtype == CR16_REG_REL || addrtype == CR16_REGP_REL)
|
|
1309 return TRUE;
|
|
1310 else
|
|
1311 return FALSE;
|
|
1312 }
|
|
1313
|
|
1314 return TRUE;
|
|
1315 }
|
|
1316
|
|
1317 /* Routines to compute costs. */
|
|
1318
|
|
1319 /* Return cost of the memory address x. */
|
|
1320 static int
|
|
1321 cr16_address_cost (rtx addr, machine_mode mode ATTRIBUTE_UNUSED,
|
|
1322 addr_space_t as ATTRIBUTE_UNUSED,
|
|
1323 bool speed ATTRIBUTE_UNUSED)
|
|
1324 {
|
|
1325 enum cr16_addrtype addrtype;
|
|
1326 struct cr16_address address;
|
|
1327 int cost = 2;
|
|
1328
|
|
1329 addrtype = cr16_decompose_address (addr, &address, 0, FALSE);
|
|
1330
|
|
1331 gcc_assert (addrtype != CR16_INVALID);
|
|
1332
|
|
1333 /* CR16_ABSOLUTE : 3
|
|
1334 CR16_REG_REL (disp !=0) : 4
|
|
1335 CR16_REG_REL (disp ==0) : 5
|
|
1336 CR16_REGP_REL (disp !=0) : 6
|
|
1337 CR16_REGP_REL (disp ==0) : 7
|
|
1338 CR16_INDEX_REGP_REL (disp !=0) : 8
|
|
1339 CR16_INDEX_REGP_REL (disp ==0) : 9. */
|
|
1340 switch (addrtype)
|
|
1341 {
|
|
1342 case CR16_ABSOLUTE:
|
|
1343 cost += 1;
|
|
1344 break;
|
|
1345 case CR16_REGP_REL:
|
|
1346 cost += 2;
|
|
1347 /* Fall through. */
|
|
1348 case CR16_REG_REL:
|
|
1349 cost += 3;
|
|
1350 if (address.disp)
|
|
1351 cost -= 1;
|
|
1352 break;
|
|
1353 case CR16_INDEX_REGP_REL:
|
|
1354 cost += 7;
|
|
1355 if (address.disp)
|
|
1356 cost -= 1;
|
|
1357 default:
|
|
1358 break;
|
|
1359 }
|
|
1360
|
|
1361 if (TARGET_DEBUG_ADDR)
|
|
1362 {
|
|
1363 fprintf (stderr, "\n======\nmacro TARGET_ADDRESS_COST = %d\n", cost);
|
|
1364 debug_rtx (addr);
|
|
1365 }
|
|
1366
|
|
1367 return cost;
|
|
1368 }
|
|
1369
|
|
1370
|
|
1371 /* Implement `TARGET_REGISTER_MOVE_COST'. */
|
|
1372 static int
|
|
1373 cr16_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
|
|
1374 reg_class_t from ATTRIBUTE_UNUSED, reg_class_t to)
|
|
1375 {
|
|
1376 return (to != GENERAL_REGS ? 8 : 2);
|
|
1377 }
|
|
1378
|
|
1379 /* Implement `TARGET_MEMORY_MOVE_COST'. */
|
|
1380
|
|
1381 /* Return the cost of moving data of mode MODE between a register of class
|
|
1382 CLASS and memory; IN is zero if the value is to be written to memory,
|
|
1383 nonzero if it is to be read in. This cost is relative to those in
|
|
1384 REGISTER_MOVE_COST. */
|
|
1385 static int
|
|
1386 cr16_memory_move_cost (machine_mode mode,
|
|
1387 reg_class_t rclass ATTRIBUTE_UNUSED,
|
|
1388 bool in ATTRIBUTE_UNUSED)
|
|
1389 {
|
|
1390 /* One LD or ST takes twice the time of a simple reg-reg move. */
|
|
1391 if (reg_classes_intersect_p (rclass, GENERAL_REGS))
|
|
1392 return (4 * cr16_hard_regno_nregs (0, mode));
|
|
1393 else
|
|
1394 return (100);
|
|
1395 }
|
|
1396
|
|
1397 /* Instruction output. */
|
|
1398
|
|
1399 /* Check if a const_double is ok for cr16 store-immediate instructions. */
|
|
1400 int
|
|
1401 cr16_const_double_ok (rtx op)
|
|
1402 {
|
|
1403 if (GET_MODE (op) == SFmode)
|
|
1404 {
|
|
1405 long l;
|
|
1406 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op), l);
|
|
1407 return UNSIGNED_INT_FITS_N_BITS (l, 4) ? 1 : 0;
|
|
1408 }
|
|
1409
|
|
1410 return ((UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_LOW (op), 4)) &&
|
|
1411 (UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_HIGH (op), 4))) ? 1 : 0;
|
|
1412 }
|
|
1413
|
|
1414 /* Returns bit position of first 0 or 1 bit.
|
|
1415 It is safe to assume val as 16-bit wide. */
|
|
1416 int
|
|
1417 cr16_operand_bit_pos (int val, int bitval)
|
|
1418 {
|
|
1419 int i;
|
|
1420 if (bitval == 0)
|
|
1421 val = ~val;
|
|
1422
|
|
1423 for (i = 0; i < 16; i++)
|
|
1424 if (val & (1 << i))
|
|
1425 break;
|
|
1426 return i;
|
|
1427 }
|
|
1428
|
|
1429 /* Implements the macro PRINT_OPERAND defined in cr16.h. */
|
|
1430 static void
|
|
1431 cr16_print_operand (FILE * file, rtx x, int code)
|
|
1432 {
|
|
1433 int ptr_dereference = 0;
|
|
1434
|
|
1435 switch (code)
|
|
1436 {
|
|
1437 case 'd':
|
|
1438 {
|
|
1439 const char *cr16_cmp_str;
|
|
1440 switch (GET_CODE (x))
|
|
1441 {
|
|
1442 /* MD: compare (reg, reg or imm) but CR16: cmp (reg or imm, reg)
|
|
1443 -> swap all non symmetric ops. */
|
|
1444 case EQ:
|
|
1445 cr16_cmp_str = "eq";
|
|
1446 break;
|
|
1447 case NE:
|
|
1448 cr16_cmp_str = "ne";
|
|
1449 break;
|
|
1450 case GT:
|
|
1451 cr16_cmp_str = "lt";
|
|
1452 break;
|
|
1453 case GTU:
|
|
1454 cr16_cmp_str = "lo";
|
|
1455 break;
|
|
1456 case LT:
|
|
1457 cr16_cmp_str = "gt";
|
|
1458 break;
|
|
1459 case LTU:
|
|
1460 cr16_cmp_str = "hi";
|
|
1461 break;
|
|
1462 case GE:
|
|
1463 cr16_cmp_str = "le";
|
|
1464 break;
|
|
1465 case GEU:
|
|
1466 cr16_cmp_str = "ls";
|
|
1467 break;
|
|
1468 case LE:
|
|
1469 cr16_cmp_str = "ge";
|
|
1470 break;
|
|
1471 case LEU:
|
|
1472 cr16_cmp_str = "hs";
|
|
1473 break;
|
|
1474 default:
|
|
1475 gcc_unreachable ();
|
|
1476 }
|
|
1477 fprintf (file, "%s", cr16_cmp_str);
|
|
1478 return;
|
|
1479 }
|
|
1480 case '$':
|
|
1481 putc ('$', file);
|
|
1482 return;
|
|
1483
|
|
1484 case 'p':
|
|
1485 if (GET_CODE (x) == REG)
|
|
1486 {
|
|
1487 /* For Push instructions, we should not print register pairs. */
|
|
1488 fprintf (file, "%s", reg_names[REGNO (x)]);
|
|
1489 return;
|
|
1490 }
|
|
1491 break;
|
|
1492
|
|
1493 case 'b':
|
|
1494 /* Print the immediate address for bal
|
|
1495 'b' is used instead of 'a' to avoid compiler calling
|
|
1496 the GO_IF_LEGITIMATE_ADDRESS which cannot
|
|
1497 perform checks on const_int code addresses as it
|
|
1498 assumes all const_int are data addresses. */
|
|
1499 fprintf (file, "0x%lx", INTVAL (x));
|
|
1500 return;
|
|
1501
|
|
1502 case 'r':
|
|
1503 /* Print bit position of first 0. */
|
|
1504 fprintf (file, "%d", cr16_operand_bit_pos (INTVAL (x), 0));
|
|
1505 return;
|
|
1506
|
|
1507 case 's':
|
|
1508 /* Print bit position of first 1. */
|
|
1509 fprintf (file, "%d", cr16_operand_bit_pos (INTVAL (x), 1));
|
|
1510 return;
|
|
1511 case 'g':
|
|
1512 /* 'g' is used for implicit mem: dereference. */
|
|
1513 ptr_dereference = 1;
|
|
1514 /* FALLTHRU */
|
|
1515 case 'f':
|
|
1516 case 0:
|
|
1517 /* default. */
|
|
1518 switch (GET_CODE (x))
|
|
1519 {
|
|
1520 case REG:
|
|
1521 if (GET_MODE_BITSIZE (GET_MODE (x)) > BITS_PER_WORD)
|
|
1522 {
|
|
1523 if (LONG_REG_P (REGNO (x)))
|
|
1524 fprintf (file, "(%s)", reg_names[REGNO (x)]);
|
|
1525 else
|
|
1526 fprintf (file, "(%s,%s)", reg_names[REGNO (x) + 1],
|
|
1527 reg_names[REGNO (x)]);
|
|
1528 }
|
|
1529 else
|
|
1530 fprintf (file, "%s", reg_names[REGNO (x)]);
|
|
1531 return;
|
|
1532
|
|
1533 case MEM:
|
|
1534 output_address (GET_MODE (x), XEXP (x, 0));
|
|
1535 return;
|
|
1536
|
|
1537 case CONST_DOUBLE:
|
|
1538 {
|
|
1539 long l;
|
|
1540
|
|
1541 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), l);
|
|
1542
|
|
1543 fprintf (file, "$0x%lx", l);
|
|
1544 return;
|
|
1545 }
|
|
1546 case CONST_INT:
|
|
1547 {
|
|
1548 fprintf (file, "$%ld", INTVAL (x));
|
|
1549 return;
|
|
1550 }
|
|
1551 case UNSPEC:
|
|
1552 switch (XINT (x, 1))
|
|
1553 {
|
|
1554 default:
|
|
1555 gcc_unreachable ();
|
|
1556 }
|
|
1557 break;
|
|
1558
|
|
1559 default:
|
|
1560 if (!ptr_dereference)
|
|
1561 {
|
|
1562 putc ('$', file);
|
|
1563 }
|
|
1564 cr16_print_operand_address (file, VOIDmode, x);
|
|
1565 return;
|
|
1566 }
|
|
1567 gcc_unreachable ();
|
|
1568 default:
|
|
1569 output_operand_lossage ("invalid %%xn code");
|
|
1570 }
|
|
1571
|
|
1572 gcc_unreachable ();
|
|
1573 }
|
|
1574
|
|
1575 /* Implements the macro PRINT_OPERAND_ADDRESS defined in cr16.h. */
|
|
1576
|
|
1577 static void
|
|
1578 cr16_print_operand_address (FILE * file, machine_mode /*mode*/, rtx addr)
|
|
1579 {
|
|
1580 enum cr16_addrtype addrtype;
|
|
1581 struct cr16_address address;
|
|
1582
|
|
1583 /* Decompose the address. Also ask it to treat address as constant. */
|
|
1584 addrtype = cr16_decompose_address (addr, &address, 0, TRUE);
|
|
1585
|
|
1586 if (address.disp && GET_CODE (address.disp) == UNSPEC)
|
|
1587 {
|
|
1588 debug_rtx (addr);
|
|
1589 }
|
|
1590
|
|
1591 switch (addrtype)
|
|
1592 {
|
|
1593 case CR16_REG_REL:
|
|
1594 if (address.disp)
|
|
1595 {
|
|
1596 if (GET_CODE (address.disp) == UNSPEC)
|
|
1597 cr16_print_operand (file, address.disp, 0);
|
|
1598 else
|
|
1599 output_addr_const (file, address.disp);
|
|
1600 }
|
|
1601 else
|
|
1602 fprintf (file, "0");
|
|
1603 fprintf (file, "(%s)", reg_names[REGNO (address.base)]);
|
|
1604 break;
|
|
1605
|
|
1606 case CR16_ABSOLUTE:
|
|
1607 if (address.disp)
|
|
1608 output_addr_const (file, address.disp);
|
|
1609 else
|
|
1610 fprintf (file, "0");
|
|
1611 break;
|
|
1612
|
|
1613 case CR16_INDEX_REGP_REL:
|
|
1614 fprintf (file, "[%s]", reg_names[REGNO (address.index)]);
|
|
1615 /* Fall through. */
|
|
1616 case CR16_REGP_REL:
|
|
1617 if (address.disp)
|
|
1618 {
|
|
1619 if (GET_CODE (address.disp) == UNSPEC)
|
|
1620 cr16_print_operand (file, address.disp, 0);
|
|
1621 else
|
|
1622 output_addr_const (file, address.disp);
|
|
1623 }
|
|
1624 else
|
|
1625 fprintf (file, "0");
|
|
1626 fprintf (file, "(%s,%s)", reg_names[REGNO (address.base) + 1],
|
|
1627 reg_names[REGNO (address.base)]);
|
|
1628 break;
|
|
1629 default:
|
|
1630 debug_rtx (addr);
|
|
1631 gcc_unreachable ();
|
|
1632 }
|
|
1633 /* Add qualifiers to the address expression that was just printed. */
|
|
1634 if (flag_pic < NEAR_PIC && address.code == 0)
|
|
1635 {
|
|
1636 if (address.data == DM_FAR)
|
|
1637 /* Addr contains SYMBOL_REF & far data ptr. */
|
|
1638 fprintf (file, "@l");
|
|
1639 else if (address.data == DM_DEFAULT)
|
|
1640 /* Addr contains SYMBOL_REF & medium data ptr. */
|
|
1641 fprintf (file, "@m");
|
|
1642 /* Addr contains SYMBOL_REF & medium data ptr. */
|
|
1643 else if (address.data == DM_NEAR)
|
|
1644 /* Addr contains SYMBOL_REF & near data ptr. */
|
|
1645 fprintf (file, "@s");
|
|
1646 }
|
|
1647 else if (flag_pic == NEAR_PIC
|
|
1648 && (address.code == 0) && (address.data == DM_FAR
|
|
1649 || address.data == DM_DEFAULT
|
|
1650 || address.data == DM_NEAR))
|
|
1651 {
|
|
1652 fprintf (file, "@l");
|
|
1653 }
|
|
1654 else if (flag_pic == NEAR_PIC && address.code == 2)
|
|
1655 {
|
|
1656 fprintf (file, "pic");
|
|
1657 }
|
|
1658 else if (flag_pic == NEAR_PIC && address.code == 1)
|
|
1659 {
|
|
1660 fprintf (file, "@cpic");
|
|
1661 }
|
|
1662
|
|
1663 else if (flag_pic == FAR_PIC && address.code == 2)
|
|
1664 {
|
|
1665 /* REVISIT: cr16 register indirect jump expects a 1-bit right shifted
|
|
1666 address ! GOTc tells assembler this symbol is a text-address
|
|
1667 This needs to be fixed in such a way that this offset is done
|
|
1668 only in the case where an address is being used for indirect jump
|
|
1669 or call. Determining the potential usage of loadd is of course not
|
|
1670 possible always. Eventually, this has to be fixed in the
|
|
1671 processor. */
|
|
1672 fprintf (file, "GOT (%s)", reg_names[PIC_OFFSET_TABLE_REGNUM]);
|
|
1673 }
|
|
1674 else if (flag_pic == FAR_PIC && address.code == 1)
|
|
1675 {
|
|
1676 fprintf (file, "@cGOT (%s)", reg_names[PIC_OFFSET_TABLE_REGNUM]);
|
|
1677 }
|
|
1678
|
|
1679 else if (flag_pic == FAR_PIC &&
|
|
1680 (address.data == DM_FAR || address.data == DM_DEFAULT
|
|
1681 || address.data == DM_NEAR))
|
|
1682 {
|
|
1683 fprintf (file, "@GOT (%s)", reg_names[PIC_OFFSET_TABLE_REGNUM]);
|
|
1684 }
|
|
1685 }
|
|
1686
|
|
1687 /* Machine description helper functions. */
|
|
1688
|
|
1689 /* Called from cr16.md. The return value depends on the parameter push_or_pop:
|
|
1690 When push_or_pop is zero -> string for push instructions of prologue.
|
|
1691 When push_or_pop is nonzero -> string for pop/popret/retx in epilogue.
|
|
1692 Relies on the assumptions:
|
|
1693 1. RA is the last register to be saved.
|
|
1694 2. The maximal value of the counter is MAX_COUNT. */
|
|
1695 char *
|
|
1696 cr16_prepare_push_pop_string (int push_or_pop)
|
|
1697 {
|
|
1698 /* j is the number of registers being saved, takes care that there won't be
|
|
1699 more than 8 in one push/pop instruction. */
|
|
1700
|
|
1701 /* For the register mask string. */
|
|
1702 static char one_inst_str[50];
|
|
1703
|
|
1704 /* i is the index of current_frame_info.save_regs[], going from 0 until
|
|
1705 current_frame_info.last_reg_to_save. */
|
|
1706 int i, start_reg;
|
|
1707 int word_cnt;
|
|
1708 int print_ra;
|
|
1709 char *return_str;
|
|
1710
|
|
1711 /* For reversing on the push instructions if there are more than one. */
|
|
1712 char *temp_str;
|
|
1713
|
|
1714 return_str = (char *) xmalloc (160);
|
|
1715 temp_str = (char *) xmalloc (160);
|
|
1716
|
|
1717 /* Initialize. */
|
|
1718 memset (return_str, 0, 3);
|
|
1719
|
|
1720 i = 0;
|
|
1721 while (i <= current_frame_info.last_reg_to_save)
|
|
1722 {
|
|
1723 /* Prepare mask for one instruction. */
|
|
1724 one_inst_str[0] = 0;
|
|
1725
|
|
1726 /* To count number of words in one instruction. */
|
|
1727 word_cnt = 0;
|
|
1728 start_reg = i;
|
|
1729 print_ra = 0;
|
|
1730 while ((word_cnt < MAX_COUNT)
|
|
1731 && (i <= current_frame_info.last_reg_to_save))
|
|
1732 {
|
|
1733 /* For each non consecutive save register,
|
|
1734 a new instruction shall be generated. */
|
|
1735 if (!current_frame_info.save_regs[i])
|
|
1736 {
|
|
1737 /* Move to next reg and break. */
|
|
1738 ++i;
|
|
1739 break;
|
|
1740 }
|
|
1741
|
|
1742 if (i == RETURN_ADDRESS_REGNUM)
|
|
1743 print_ra = 1;
|
|
1744 else
|
|
1745 {
|
|
1746 /* Check especially if adding 2 does not cross the MAX_COUNT. */
|
|
1747 if ((word_cnt + ((i < CR16_FIRST_DWORD_REGISTER) ? 1 : 2))
|
|
1748 >= MAX_COUNT)
|
|
1749 break;
|
|
1750 /* Increase word count by 2 for long registers except RA. */
|
|
1751 word_cnt += ((i < CR16_FIRST_DWORD_REGISTER) ? 1 : 2);
|
|
1752 }
|
|
1753 ++i;
|
|
1754 }
|
|
1755
|
|
1756 /* No need to generate any instruction as
|
|
1757 no register or RA needs to be saved. */
|
|
1758 if ((word_cnt == 0) && (print_ra == 0))
|
|
1759 continue;
|
|
1760
|
|
1761 /* Now prepare the instruction operands. */
|
|
1762 if (word_cnt > 0)
|
|
1763 {
|
|
1764 sprintf (one_inst_str, "$%d, %s", word_cnt, reg_names[start_reg]);
|
|
1765 if (print_ra)
|
|
1766 strcat (one_inst_str, ", ra");
|
|
1767 }
|
|
1768 else
|
|
1769 strcat (one_inst_str, "ra");
|
|
1770
|
|
1771 if (push_or_pop == 1)
|
|
1772 {
|
|
1773 /* Pop instruction. */
|
|
1774 if (print_ra && !cr16_interrupt_function_p ()
|
|
1775 && !crtl->calls_eh_return)
|
|
1776 /* Print popret if RA is saved and its not a interrupt
|
|
1777 function. */
|
|
1778 strcpy (temp_str, "\n\tpopret\t");
|
|
1779 else
|
|
1780 strcpy (temp_str, "\n\tpop\t");
|
|
1781
|
|
1782 strcat (temp_str, one_inst_str);
|
|
1783
|
|
1784 /* Add the pop instruction list. */
|
|
1785 strcat (return_str, temp_str);
|
|
1786 }
|
|
1787 else
|
|
1788 {
|
|
1789 /* Push instruction. */
|
|
1790 strcpy (temp_str, "\n\tpush\t");
|
|
1791 strcat (temp_str, one_inst_str);
|
|
1792
|
|
1793 /* We need to reverse the order of the instructions if there
|
|
1794 are more than one. (since the pop will not be reversed in
|
|
1795 the epilogue. */
|
|
1796 strcat (temp_str, return_str);
|
|
1797 strcpy (return_str, temp_str);
|
|
1798 }
|
|
1799 }
|
|
1800
|
|
1801 if (push_or_pop == 1)
|
|
1802 {
|
|
1803 /* POP. */
|
|
1804 if (cr16_interrupt_function_p ())
|
|
1805 strcat (return_str, "\n\tretx\n");
|
|
1806 else if (crtl->calls_eh_return)
|
|
1807 {
|
|
1808 /* Add stack adjustment before returning to exception handler
|
|
1809 NOTE: EH_RETURN_STACKADJ_RTX must refer to (r5, r4). */
|
|
1810 strcat (return_str, "\n\taddd\t (r5, r4), (sp)\t\n");
|
|
1811 strcat (return_str, "\n\tjump\t (ra)\n");
|
|
1812
|
|
1813 /* But before anything else, undo the adjustment addition done in
|
|
1814 cr16_expand_epilogue (). */
|
|
1815 strcpy (temp_str, "\n\tsubd\t (r5, r4), (sp)\t\n");
|
|
1816 strcat (temp_str, return_str);
|
|
1817 strcpy (return_str, temp_str);
|
|
1818 }
|
|
1819 else if (!FUNC_IS_NORETURN_P (current_function_decl)
|
|
1820 && !(current_frame_info.save_regs[RETURN_ADDRESS_REGNUM]))
|
|
1821 strcat (return_str, "\n\tjump\t (ra)\n");
|
|
1822 }
|
|
1823
|
|
1824 /* Skip the newline and the tab in the start of return_str. */
|
|
1825 return_str += 2;
|
|
1826 return return_str;
|
|
1827 }
|
|
1828
|
|
1829
|
|
1830 /* Generate DWARF2 annotation for multi-push instruction. */
|
|
1831 static void
|
|
1832 cr16_create_dwarf_for_multi_push (rtx insn)
|
|
1833 {
|
|
1834 rtx dwarf, reg, tmp;
|
|
1835 int i, j, from, to, word_cnt, dwarf_par_index, inc;
|
|
1836 machine_mode mode;
|
|
1837 int num_regs = 0, offset = 0, split_here = 0, total_push_bytes = 0;
|
|
1838
|
|
1839 for (i = 0; i <= current_frame_info.last_reg_to_save; ++i)
|
|
1840 {
|
|
1841 if (current_frame_info.save_regs[i])
|
|
1842 {
|
|
1843 ++num_regs;
|
|
1844 if (i < CR16_FIRST_DWORD_REGISTER)
|
|
1845 total_push_bytes += 2;
|
|
1846 else
|
|
1847 total_push_bytes += 4;
|
|
1848 }
|
|
1849 }
|
|
1850
|
|
1851 if (!num_regs)
|
|
1852 return;
|
|
1853
|
|
1854 dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_regs + 1));
|
|
1855 dwarf_par_index = num_regs;
|
|
1856
|
|
1857 from = current_frame_info.last_reg_to_save + 1;
|
|
1858 to = current_frame_info.last_reg_to_save;
|
|
1859 word_cnt = 0;
|
|
1860
|
|
1861 for (i = current_frame_info.last_reg_to_save; i >= 0;)
|
|
1862 {
|
131
|
1863 if (!current_frame_info.save_regs[i] || i == 0 || split_here)
|
111
|
1864 {
|
|
1865 /* This block of regs is pushed in one instruction. */
|
131
|
1866 if (i == 0 && current_frame_info.save_regs[i])
|
111
|
1867 from = 0;
|
|
1868
|
|
1869 for (j = to; j >= from; --j)
|
|
1870 {
|
|
1871 if (j < CR16_FIRST_DWORD_REGISTER)
|
|
1872 {
|
|
1873 mode = HImode;
|
|
1874 inc = 1;
|
|
1875 }
|
|
1876 else
|
|
1877 {
|
|
1878 mode = SImode;
|
|
1879 inc = 2;
|
|
1880 }
|
|
1881 reg = gen_rtx_REG (mode, j);
|
|
1882 offset += 2 * inc;
|
|
1883 tmp = gen_rtx_SET (gen_frame_mem (mode,
|
|
1884 plus_constant
|
|
1885 (Pmode, stack_pointer_rtx,
|
|
1886 total_push_bytes - offset)),
|
|
1887 reg);
|
|
1888 RTX_FRAME_RELATED_P (tmp) = 1;
|
|
1889 XVECEXP (dwarf, 0, dwarf_par_index--) = tmp;
|
|
1890 }
|
|
1891 from = i;
|
|
1892 to = --i;
|
|
1893 split_here = 0;
|
|
1894 word_cnt = 0;
|
|
1895 continue;
|
|
1896 }
|
|
1897
|
|
1898 if (i != RETURN_ADDRESS_REGNUM)
|
|
1899 {
|
|
1900 inc = (i < CR16_FIRST_DWORD_REGISTER) ? 1 : 2;
|
|
1901 if (word_cnt + inc >= MAX_COUNT || FRAME_POINTER_REGNUM == i)
|
|
1902 {
|
|
1903 split_here = 1;
|
|
1904 from = i;
|
|
1905 continue;
|
|
1906 }
|
|
1907 word_cnt += inc;
|
|
1908 }
|
|
1909
|
|
1910 from = i--;
|
|
1911 }
|
|
1912
|
|
1913 tmp = gen_rtx_SET (stack_pointer_rtx,
|
|
1914 gen_rtx_PLUS (SImode, stack_pointer_rtx,
|
|
1915 GEN_INT (-offset)));
|
|
1916 RTX_FRAME_RELATED_P (tmp) = 1;
|
|
1917 XVECEXP (dwarf, 0, 0) = tmp;
|
|
1918
|
|
1919 add_reg_note (insn, REG_FRAME_RELATED_EXPR, dwarf);
|
|
1920 }
|
|
1921
|
|
1922 /*
|
|
1923 CompactRISC CR16 Architecture stack layout:
|
|
1924
|
|
1925 0 +---------------------
|
|
1926 |
|
|
1927 .
|
|
1928 .
|
|
1929 |
|
|
1930 +==================== Sp (x) = Ap (x+1)
|
|
1931 A | Args for functions
|
|
1932 | | called by X and Dynamically
|
|
1933 | | Dynamic allocations allocated and
|
|
1934 | | (alloca, variable deallocated
|
|
1935 Stack | length arrays).
|
|
1936 grows +-------------------- Fp (x)
|
|
1937 down| | Local variables of X
|
|
1938 ward| +--------------------
|
|
1939 | | Regs saved for X-1
|
|
1940 | +==================== Sp (x-1) = Ap (x)
|
|
1941 | Args for func X
|
|
1942 | pushed by X-1
|
|
1943 +-------------------- Fp (x-1)
|
|
1944 |
|
|
1945 |
|
|
1946 V
|
|
1947 */
|
|
1948 void
|
|
1949 cr16_expand_prologue (void)
|
|
1950 {
|
|
1951 rtx insn;
|
|
1952
|
|
1953 cr16_compute_frame ();
|
|
1954 cr16_compute_save_regs ();
|
|
1955
|
|
1956 /* If there is no need in push and adjustment to sp, return. */
|
|
1957 if ((current_frame_info.total_size + current_frame_info.reg_size) == 0)
|
|
1958 return;
|
|
1959
|
|
1960 if (current_frame_info.last_reg_to_save != -1)
|
|
1961 {
|
|
1962 /* If there are registers to push. */
|
|
1963 insn = emit_insn (gen_push_for_prologue
|
|
1964 (GEN_INT (current_frame_info.reg_size)));
|
|
1965 cr16_create_dwarf_for_multi_push (insn);
|
|
1966 RTX_FRAME_RELATED_P (insn) = 1;
|
|
1967 }
|
|
1968
|
|
1969
|
|
1970 if (current_frame_info.total_size > 0)
|
|
1971 {
|
|
1972 insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
|
1973 GEN_INT (-current_frame_info.total_size)));
|
|
1974 RTX_FRAME_RELATED_P (insn) = 1;
|
|
1975 }
|
|
1976
|
|
1977 if (frame_pointer_needed)
|
|
1978 {
|
|
1979 /* Initialize the frame pointer with the value of the stack pointer
|
|
1980 pointing now to the locals. */
|
|
1981 insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
|
|
1982 }
|
|
1983 }
|
|
1984
|
|
1985 /* Generate insn that updates the stack for local variables and padding
|
|
1986 for registers we save. - Generate the appropriate return insn. */
|
|
1987 void
|
|
1988 cr16_expand_epilogue (void)
|
|
1989 {
|
|
1990 rtx insn;
|
|
1991
|
|
1992 /* Nonzero if we need to return and pop only RA. This will generate a
|
|
1993 different insn. This differentiate is for the peepholes for call as
|
|
1994 last statement in function. */
|
|
1995 int only_popret_RA = (current_frame_info.save_regs[RETURN_ADDRESS_REGNUM]
|
|
1996 && (current_frame_info.reg_size
|
|
1997 == CR16_UNITS_PER_DWORD));
|
|
1998
|
|
1999 if (frame_pointer_needed)
|
|
2000 {
|
|
2001 /* Restore the stack pointer with the frame pointers value. */
|
|
2002 insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
|
|
2003 }
|
|
2004
|
|
2005 if (current_frame_info.total_size > 0)
|
|
2006 {
|
|
2007 insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
|
2008 GEN_INT (current_frame_info.total_size)));
|
|
2009 RTX_FRAME_RELATED_P (insn) = 1;
|
|
2010 }
|
|
2011
|
|
2012 if (crtl->calls_eh_return)
|
|
2013 {
|
|
2014 /* Add this here so that (r5, r4) is actually loaded with the adjustment
|
|
2015 value; otherwise, the load might be optimized away...
|
|
2016 NOTE: remember to subtract the adjustment before popping the regs
|
|
2017 and add it back before returning. */
|
|
2018 insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
|
2019 EH_RETURN_STACKADJ_RTX));
|
|
2020 }
|
|
2021
|
|
2022 if (cr16_interrupt_function_p ())
|
|
2023 {
|
|
2024 insn = emit_jump_insn (gen_interrupt_return ());
|
|
2025 RTX_FRAME_RELATED_P (insn) = 1;
|
|
2026 }
|
|
2027 else if (crtl->calls_eh_return)
|
|
2028 {
|
|
2029 /* Special case, pop what's necessary, adjust SP and jump to (RA). */
|
|
2030 insn = emit_jump_insn (gen_pop_and_popret_return
|
|
2031 (GEN_INT (current_frame_info.reg_size)));
|
|
2032 RTX_FRAME_RELATED_P (insn) = 1;
|
|
2033 }
|
|
2034 else if (current_frame_info.last_reg_to_save == -1)
|
|
2035 /* Nothing to pop. */
|
|
2036 /* Don't output jump for interrupt routine, only retx. */
|
|
2037 emit_jump_insn (gen_jump_return ());
|
|
2038 else if (only_popret_RA)
|
|
2039 {
|
|
2040 insn = emit_jump_insn (gen_popret_RA_return ());
|
|
2041 RTX_FRAME_RELATED_P (insn) = 1;
|
|
2042 }
|
|
2043 else
|
|
2044 {
|
|
2045 insn = emit_jump_insn (gen_pop_and_popret_return
|
|
2046 (GEN_INT (current_frame_info.reg_size)));
|
|
2047 RTX_FRAME_RELATED_P (insn) = 1;
|
|
2048 }
|
|
2049 }
|
|
2050
|
|
2051 /* Implements FRAME_POINTER_REQUIRED. */
|
|
2052 static bool
|
|
2053 cr16_frame_pointer_required (void)
|
|
2054 {
|
|
2055 return (cfun->calls_alloca || crtl->calls_eh_return
|
|
2056 || cfun->has_nonlocal_label || crtl->calls_eh_return);
|
|
2057 }
|
|
2058
|
|
2059 static bool
|
|
2060 cr16_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
|
|
2061 {
|
|
2062 return (to == STACK_POINTER_REGNUM ? !frame_pointer_needed : true);
|
|
2063 }
|
|
2064
|
|
2065
|
|
2066 /* A C compound statement that attempts to replace X with
|
|
2067 a valid memory address for an operand of mode MODE. WIN
|
|
2068 will be a C statement label elsewhere in the code.
|
|
2069 X will always be the result of a call to break_out_memory_refs (),
|
|
2070 and OLDX will be the operand that was given to that function to
|
|
2071 produce X.
|
|
2072 The code generated by this macro should not alter the
|
|
2073 substructure of X. If it transforms X into a more legitimate form,
|
|
2074 it should assign X (which will always be a C variable) a new value. */
|
|
2075 static rtx
|
|
2076 cr16_legitimize_address (rtx x, rtx orig_x ATTRIBUTE_UNUSED,
|
|
2077 machine_mode mode ATTRIBUTE_UNUSED)
|
|
2078 {
|
|
2079 if (flag_pic)
|
|
2080 return legitimize_pic_address (orig_x, mode, NULL_RTX);
|
|
2081 else
|
|
2082 return x;
|
|
2083 }
|
|
2084
|
|
2085 /* Implement TARGET_LEGITIMATE_CONSTANT_P
|
|
2086 Nonzero if X is a legitimate constant for an immediate
|
|
2087 operand on the target machine. You can assume that X
|
|
2088 satisfies CONSTANT_P. In cr16c treat legitimize float
|
|
2089 constant as an immediate operand. */
|
|
2090 static bool
|
|
2091 cr16_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED,
|
|
2092 rtx x ATTRIBUTE_UNUSED)
|
|
2093 {
|
|
2094 return 1;
|
|
2095 }
|
|
2096
|
|
2097 void
|
|
2098 notice_update_cc (rtx exp)
|
|
2099 {
|
|
2100 if (GET_CODE (exp) == SET)
|
|
2101 {
|
|
2102 /* Jumps do not alter the cc's. */
|
|
2103 if (SET_DEST (exp) == pc_rtx)
|
|
2104 return;
|
|
2105
|
|
2106 /* Moving register or memory into a register:
|
|
2107 it doesn't alter the cc's, but it might invalidate
|
|
2108 the RTX's which we remember the cc's came from.
|
|
2109 (Note that moving a constant 0 or 1 MAY set the cc's). */
|
|
2110 if (REG_P (SET_DEST (exp))
|
|
2111 && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM))
|
|
2112 {
|
|
2113 return;
|
|
2114 }
|
|
2115
|
|
2116 /* Moving register into memory doesn't alter the cc's.
|
|
2117 It may invalidate the RTX's which we remember the cc's came from. */
|
|
2118 if (GET_CODE (SET_DEST (exp)) == MEM && REG_P (SET_SRC (exp)))
|
|
2119 {
|
|
2120 return;
|
|
2121 }
|
|
2122 }
|
|
2123
|
|
2124 CC_STATUS_INIT;
|
|
2125 return;
|
|
2126 }
|
|
2127
|
|
2128 static scalar_int_mode
|
|
2129 cr16_unwind_word_mode (void)
|
|
2130 {
|
|
2131 return SImode;
|
|
2132 }
|
|
2133
|
|
2134 /* Helper function for md file. This function is used to emit arithmetic
|
|
2135 DI instructions. The argument "num" decides which instruction to be
|
|
2136 printed. */
|
|
2137 const char *
|
|
2138 cr16_emit_add_sub_di (rtx *operands, enum rtx_code code)
|
|
2139 {
|
|
2140 rtx lo_op[2] ;
|
|
2141 rtx hi0_op[2] ;
|
|
2142 rtx hi1_op[2] ;
|
|
2143
|
|
2144 lo_op[0] = gen_lowpart (SImode, operands[0]);
|
|
2145 hi0_op[0] = simplify_gen_subreg (HImode, operands[0], DImode, 4);
|
|
2146 hi1_op[0] = simplify_gen_subreg (HImode, operands[0], DImode, 6);
|
|
2147
|
|
2148 lo_op[1] = gen_lowpart (SImode, operands[2]);
|
|
2149 hi0_op[1] = simplify_gen_subreg (HImode, operands[2], DImode, 4);
|
|
2150 hi1_op[1] = simplify_gen_subreg (HImode, operands[2], DImode, 6);
|
|
2151
|
|
2152 switch (code)
|
|
2153 {
|
|
2154 case PLUS:
|
|
2155 {
|
|
2156 output_asm_insn ("addd\t%1, %0", lo_op) ;
|
|
2157 output_asm_insn ("addcw\t%1, %0", hi0_op) ;
|
|
2158 output_asm_insn ("addcw\t%1, %0", hi1_op) ;
|
|
2159 break;
|
|
2160 }
|
|
2161 case MINUS:
|
|
2162 {
|
|
2163 output_asm_insn ("subd\t%1, %0", lo_op) ;
|
|
2164 output_asm_insn ("subcw\t%1, %0", hi0_op) ;
|
|
2165 output_asm_insn ("subcw\t%1, %0", hi1_op) ;
|
|
2166 break;
|
|
2167 }
|
|
2168 default:
|
|
2169 break;
|
|
2170 }
|
|
2171
|
|
2172 return "";
|
|
2173 }
|
|
2174
|
|
2175
|
|
2176 /* Helper function for md file. This function is used to emit logical
|
|
2177 DI instructions. The argument "num" decides which instruction to be
|
|
2178 printed. */
|
|
2179 const char *
|
|
2180 cr16_emit_logical_di (rtx *operands, enum rtx_code code)
|
|
2181 {
|
|
2182 rtx lo_op[2] ;
|
|
2183 rtx hi_op[2] ;
|
|
2184
|
|
2185 lo_op[0] = gen_lowpart (SImode, operands[0]);
|
|
2186 hi_op[0] = simplify_gen_subreg (SImode, operands[0], DImode, 4);
|
|
2187
|
|
2188 lo_op[1] = gen_lowpart (SImode, operands[2]);
|
|
2189 hi_op[1] = simplify_gen_subreg (SImode, operands[2], DImode, 4);
|
|
2190
|
|
2191 switch (code)
|
|
2192 {
|
|
2193 case AND:
|
|
2194 {
|
|
2195 output_asm_insn ("andd\t%1, %0", lo_op) ;
|
|
2196 output_asm_insn ("andd\t%1, %0", hi_op) ;
|
|
2197 return "";
|
|
2198 }
|
|
2199 case IOR:
|
|
2200 {
|
|
2201 output_asm_insn ("ord\t%1, %0", lo_op) ;
|
|
2202 output_asm_insn ("ord\t%1, %0", hi_op) ;
|
|
2203 return "";
|
|
2204 }
|
|
2205 case XOR:
|
|
2206 {
|
|
2207 output_asm_insn ("xord\t%1, %0", lo_op) ;
|
|
2208 output_asm_insn ("xord\t%1, %0", hi_op) ;
|
|
2209 return "";
|
|
2210 }
|
|
2211 default:
|
|
2212 break;
|
|
2213 }
|
|
2214
|
|
2215 return "";
|
|
2216 }
|
|
2217
|
131
|
2218 /* Implement PUSH_ROUNDING. */
|
|
2219
|
|
2220 poly_int64
|
|
2221 cr16_push_rounding (poly_int64 bytes)
|
|
2222 {
|
|
2223 return (bytes + 1) & ~1;
|
|
2224 }
|
|
2225
|
111
|
2226 /* Initialize 'targetm' variable which contains pointers to functions
|
|
2227 and data relating to the target machine. */
|
|
2228
|
|
2229 struct gcc_target targetm = TARGET_INITIALIZER;
|