Mercurial > hg > CbC > CbC_gcc
annotate gcc/config/pdp11/pdp11.c @ 63:b7f97abdc517 gcc-4.6-20100522
update gcc from gcc-4.5.0 to gcc-4.6
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 24 May 2010 12:47:05 +0900 |
parents | 77e2b8dfacca |
children | f6334be47118 |
rev | line source |
---|---|
0 | 1 /* Subroutines for gcc2 for pdp11. |
2 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2004, 2005, | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
3 2006, 2007, 2008, 2009 Free Software Foundation, Inc. |
0 | 4 Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at). |
5 | |
6 This file is part of GCC. | |
7 | |
8 GCC is free software; you can redistribute it and/or modify | |
9 it under the terms of the GNU General Public License as published by | |
10 the Free Software Foundation; either version 3, or (at your option) | |
11 any later version. | |
12 | |
13 GCC is distributed in the hope that it will be useful, | |
14 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 GNU General Public License for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with GCC; see the file COPYING3. If not see | |
20 <http://www.gnu.org/licenses/>. */ | |
21 | |
22 #include "config.h" | |
23 #include "system.h" | |
24 #include "coretypes.h" | |
25 #include "tm.h" | |
26 #include "rtl.h" | |
27 #include "regs.h" | |
28 #include "hard-reg-set.h" | |
29 #include "insn-config.h" | |
30 #include "conditions.h" | |
31 #include "function.h" | |
32 #include "output.h" | |
33 #include "insn-attr.h" | |
34 #include "flags.h" | |
35 #include "recog.h" | |
36 #include "tree.h" | |
37 #include "expr.h" | |
38 #include "toplev.h" | |
39 #include "tm_p.h" | |
40 #include "target.h" | |
41 #include "target-def.h" | |
42 #include "df.h" | |
43 | |
44 /* | |
45 #define FPU_REG_P(X) ((X)>=8 && (X)<14) | |
46 #define CPU_REG_P(X) ((X)>=0 && (X)<8) | |
47 */ | |
48 | |
49 /* this is the current value returned by the macro FIRST_PARM_OFFSET | |
50 defined in tm.h */ | |
51 int current_first_parm_offset; | |
52 | |
53 /* Routines to encode/decode pdp11 floats */ | |
54 static void encode_pdp11_f (const struct real_format *fmt, | |
55 long *, const REAL_VALUE_TYPE *); | |
56 static void decode_pdp11_f (const struct real_format *, | |
57 REAL_VALUE_TYPE *, const long *); | |
58 static void encode_pdp11_d (const struct real_format *fmt, | |
59 long *, const REAL_VALUE_TYPE *); | |
60 static void decode_pdp11_d (const struct real_format *, | |
61 REAL_VALUE_TYPE *, const long *); | |
62 | |
63 /* These two are taken from the corresponding vax descriptors | |
64 in real.c, changing only the encode/decode routine pointers. */ | |
65 const struct real_format pdp11_f_format = | |
66 { | |
67 encode_pdp11_f, | |
68 decode_pdp11_f, | |
69 2, | |
70 1, | |
71 24, | |
72 24, | |
73 -127, | |
74 127, | |
75 15, | |
76 false, | |
77 false, | |
78 false, | |
79 false, | |
80 false, | |
81 false, | |
82 false, | |
83 false | |
84 }; | |
85 | |
86 const struct real_format pdp11_d_format = | |
87 { | |
88 encode_pdp11_d, | |
89 decode_pdp11_d, | |
90 2, | |
91 1, | |
92 56, | |
93 56, | |
94 -127, | |
95 127, | |
96 15, | |
97 false, | |
98 false, | |
99 false, | |
100 false, | |
101 false, | |
102 false, | |
103 false, | |
104 false | |
105 }; | |
106 | |
107 static void | |
108 encode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, | |
109 const REAL_VALUE_TYPE *r) | |
110 { | |
111 (*vax_f_format.encode) (fmt, buf, r); | |
112 buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); | |
113 } | |
114 | |
115 static void | |
116 decode_pdp11_f (const struct real_format *fmt ATTRIBUTE_UNUSED, | |
117 REAL_VALUE_TYPE *r, const long *buf) | |
118 { | |
119 long tbuf; | |
120 tbuf = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); | |
121 (*vax_f_format.decode) (fmt, r, &tbuf); | |
122 } | |
123 | |
124 static void | |
125 encode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, | |
126 const REAL_VALUE_TYPE *r) | |
127 { | |
128 (*vax_d_format.encode) (fmt, buf, r); | |
129 buf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); | |
130 buf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16); | |
131 } | |
132 | |
133 static void | |
134 decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, | |
135 REAL_VALUE_TYPE *r, const long *buf) | |
136 { | |
137 long tbuf[2]; | |
138 tbuf[0] = ((buf[0] >> 16) & 0xffff) | ((buf[0] & 0xffff) << 16); | |
139 tbuf[1] = ((buf[1] >> 16) & 0xffff) | ((buf[1] & 0xffff) << 16); | |
140 (*vax_d_format.decode) (fmt, r, tbuf); | |
141 } | |
142 | |
143 /* This is where the condition code register lives. */ | |
144 /* rtx cc0_reg_rtx; - no longer needed? */ | |
145 | |
146 static bool pdp11_handle_option (size_t, const char *, int); | |
147 static rtx find_addr_reg (rtx); | |
148 static const char *singlemove_string (rtx *); | |
149 static bool pdp11_assemble_integer (rtx, unsigned int, int); | |
150 static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT); | |
151 static void pdp11_output_function_epilogue (FILE *, HOST_WIDE_INT); | |
152 static bool pdp11_rtx_costs (rtx, int, int, int *, bool); | |
153 static bool pdp11_return_in_memory (const_tree, const_tree); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
154 static void pdp11_trampoline_init (rtx, tree, rtx); |
0 | 155 |
156 /* Initialize the GCC target structure. */ | |
157 #undef TARGET_ASM_BYTE_OP | |
158 #define TARGET_ASM_BYTE_OP NULL | |
159 #undef TARGET_ASM_ALIGNED_HI_OP | |
160 #define TARGET_ASM_ALIGNED_HI_OP NULL | |
161 #undef TARGET_ASM_ALIGNED_SI_OP | |
162 #define TARGET_ASM_ALIGNED_SI_OP NULL | |
163 #undef TARGET_ASM_INTEGER | |
164 #define TARGET_ASM_INTEGER pdp11_assemble_integer | |
165 | |
166 #undef TARGET_ASM_FUNCTION_PROLOGUE | |
167 #define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue | |
168 #undef TARGET_ASM_FUNCTION_EPILOGUE | |
169 #define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue | |
170 | |
171 #undef TARGET_ASM_OPEN_PAREN | |
172 #define TARGET_ASM_OPEN_PAREN "[" | |
173 #undef TARGET_ASM_CLOSE_PAREN | |
174 #define TARGET_ASM_CLOSE_PAREN "]" | |
175 | |
176 #undef TARGET_DEFAULT_TARGET_FLAGS | |
177 #define TARGET_DEFAULT_TARGET_FLAGS \ | |
178 (MASK_FPU | MASK_45 | MASK_ABSHI_BUILTIN | TARGET_UNIX_ASM_DEFAULT) | |
179 #undef TARGET_HANDLE_OPTION | |
180 #define TARGET_HANDLE_OPTION pdp11_handle_option | |
181 | |
182 #undef TARGET_RTX_COSTS | |
183 #define TARGET_RTX_COSTS pdp11_rtx_costs | |
184 | |
185 #undef TARGET_RETURN_IN_MEMORY | |
186 #define TARGET_RETURN_IN_MEMORY pdp11_return_in_memory | |
187 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
188 #undef TARGET_TRAMPOLINE_INIT |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
189 #define TARGET_TRAMPOLINE_INIT pdp11_trampoline_init |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
190 |
0 | 191 struct gcc_target targetm = TARGET_INITIALIZER; |
192 | |
193 /* Implement TARGET_HANDLE_OPTION. */ | |
194 | |
195 static bool | |
196 pdp11_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED, | |
197 int value ATTRIBUTE_UNUSED) | |
198 { | |
199 switch (code) | |
200 { | |
201 case OPT_m10: | |
202 target_flags &= ~(MASK_40 | MASK_45); | |
203 return true; | |
204 | |
205 default: | |
206 return true; | |
207 } | |
208 } | |
209 | |
210 /* Nonzero if OP is a valid second operand for an arithmetic insn. */ | |
211 | |
212 int | |
213 arith_operand (rtx op, enum machine_mode mode) | |
214 { | |
215 return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); | |
216 } | |
217 | |
218 int | |
219 const_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
220 { | |
221 return (GET_CODE (op) == CONST_INT); | |
222 } | |
223 | |
224 int | |
225 immediate15_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
226 { | |
227 return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000)); | |
228 } | |
229 | |
230 int | |
231 expand_shift_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
232 { | |
233 return (GET_CODE (op) == CONST_INT | |
234 && abs (INTVAL(op)) > 1 | |
235 && abs (INTVAL(op)) <= 4); | |
236 } | |
237 | |
238 /* | |
239 stream is a stdio stream to output the code to. | |
240 size is an int: how many units of temporary storage to allocate. | |
241 Refer to the array `regs_ever_live' to determine which registers | |
242 to save; `regs_ever_live[I]' is nonzero if register number I | |
243 is ever used in the function. This macro is responsible for | |
244 knowing which registers should not be saved even if used. | |
245 */ | |
246 | |
247 static void | |
248 pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size) | |
249 { | |
250 HOST_WIDE_INT fsize = ((size) + 1) & ~1; | |
251 int regno; | |
252 int via_ac = -1; | |
253 | |
254 fprintf (stream, | |
255 "\n\t; /* function prologue %s*/\n", | |
256 current_function_name ()); | |
257 | |
258 /* if we are outputting code for main, | |
259 the switch FPU to right mode if TARGET_FPU */ | |
260 if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU) | |
261 { | |
262 fprintf(stream, | |
263 "\t;/* switch cpu to double float, single integer */\n"); | |
264 fprintf(stream, "\tsetd\n"); | |
265 fprintf(stream, "\tseti\n\n"); | |
266 } | |
267 | |
268 if (frame_pointer_needed) | |
269 { | |
270 fprintf(stream, "\tmov r5, -(sp)\n"); | |
271 fprintf(stream, "\tmov sp, r5\n"); | |
272 } | |
273 else | |
274 { | |
275 /* DON'T SAVE FP */ | |
276 } | |
277 | |
278 /* make frame */ | |
279 if (fsize) | |
280 asm_fprintf (stream, "\tsub $%#wo, sp\n", fsize); | |
281 | |
282 /* save CPU registers */ | |
283 for (regno = 0; regno < 8; regno++) | |
284 if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) | |
285 if (! ((regno == FRAME_POINTER_REGNUM) | |
286 && frame_pointer_needed)) | |
287 fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]); | |
288 /* fpu regs saving */ | |
289 | |
290 /* via_ac specifies the ac to use for saving ac4, ac5 */ | |
291 via_ac = -1; | |
292 | |
293 for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++) | |
294 { | |
295 /* ac0 - ac3 */ | |
296 if (LOAD_FPU_REG_P(regno) | |
297 && df_regs_ever_live_p (regno) | |
298 && ! call_used_regs[regno]) | |
299 { | |
300 fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]); | |
301 via_ac = regno; | |
302 } | |
303 | |
304 /* maybe make ac4, ac5 call used regs?? */ | |
305 /* ac4 - ac5 */ | |
306 if (NO_LOAD_FPU_REG_P(regno) | |
307 && df_regs_ever_live_p (regno) | |
308 && ! call_used_regs[regno]) | |
309 { | |
310 gcc_assert (via_ac != -1); | |
311 fprintf (stream, "\tldd %s, %s\n", | |
312 reg_names[regno], reg_names[via_ac]); | |
313 fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]); | |
314 } | |
315 } | |
316 | |
317 fprintf (stream, "\t;/* end of prologue */\n\n"); | |
318 } | |
319 | |
320 /* | |
321 The function epilogue should not depend on the current stack pointer! | |
322 It should use the frame pointer only. This is mandatory because | |
323 of alloca; we also take advantage of it to omit stack adjustments | |
324 before returning. */ | |
325 | |
326 /* maybe we can make leaf functions faster by switching to the | |
327 second register file - this way we don't have to save regs! | |
328 leaf functions are ~ 50% of all functions (dynamically!) | |
329 | |
330 set/clear bit 11 (dec. 2048) of status word for switching register files - | |
331 but how can we do this? the pdp11/45 manual says bit may only | |
332 be set (p.24), but not cleared! | |
333 | |
334 switching to kernel is probably more expensive, so we'll leave it | |
335 like this and not use the second set of registers... | |
336 | |
337 maybe as option if you want to generate code for kernel mode? */ | |
338 | |
339 static void | |
340 pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size) | |
341 { | |
342 HOST_WIDE_INT fsize = ((size) + 1) & ~1; | |
343 int i, j, k; | |
344 | |
345 int via_ac; | |
346 | |
347 fprintf (stream, "\n\t; /*function epilogue */\n"); | |
348 | |
349 if (frame_pointer_needed) | |
350 { | |
351 /* hope this is safe - m68k does it also .... */ | |
352 df_set_regs_ever_live (FRAME_POINTER_REGNUM, false); | |
353 | |
354 for (i =7, j = 0 ; i >= 0 ; i--) | |
355 if (df_regs_ever_live_p (i) && ! call_used_regs[i]) | |
356 j++; | |
357 | |
358 /* remember # of pushed bytes for CPU regs */ | |
359 k = 2*j; | |
360 | |
361 /* change fp -> r5 due to the compile error on libgcc2.c */ | |
362 for (i =7 ; i >= 0 ; i--) | |
363 if (df_regs_ever_live_p (i) && ! call_used_regs[i]) | |
364 fprintf(stream, "\tmov %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", | |
365 (-fsize-2*j--)&0xffff, reg_names[i]); | |
366 | |
367 /* get ACs */ | |
368 via_ac = FIRST_PSEUDO_REGISTER -1; | |
369 | |
370 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) | |
371 if (df_regs_ever_live_p (i) && ! call_used_regs[i]) | |
372 { | |
373 via_ac = i; | |
374 k += 8; | |
375 } | |
376 | |
377 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) | |
378 { | |
379 if (LOAD_FPU_REG_P(i) | |
380 && df_regs_ever_live_p (i) | |
381 && ! call_used_regs[i]) | |
382 { | |
383 fprintf(stream, "\tldd %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", | |
384 (-fsize-k)&0xffff, reg_names[i]); | |
385 k -= 8; | |
386 } | |
387 | |
388 if (NO_LOAD_FPU_REG_P(i) | |
389 && df_regs_ever_live_p (i) | |
390 && ! call_used_regs[i]) | |
391 { | |
392 gcc_assert (LOAD_FPU_REG_P(via_ac)); | |
393 | |
394 fprintf(stream, "\tldd %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", | |
395 (-fsize-k)&0xffff, reg_names[via_ac]); | |
396 fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]); | |
397 k -= 8; | |
398 } | |
399 } | |
400 | |
401 fprintf(stream, "\tmov r5, sp\n"); | |
402 fprintf (stream, "\tmov (sp)+, r5\n"); | |
403 } | |
404 else | |
405 { | |
406 via_ac = FIRST_PSEUDO_REGISTER -1; | |
407 | |
408 /* get ACs */ | |
409 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) | |
410 if (df_regs_ever_live_p (i) && call_used_regs[i]) | |
411 via_ac = i; | |
412 | |
413 for (i = FIRST_PSEUDO_REGISTER; i > 7; i--) | |
414 { | |
415 if (LOAD_FPU_REG_P(i) | |
416 && df_regs_ever_live_p (i) | |
417 && ! call_used_regs[i]) | |
418 fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]); | |
419 | |
420 if (NO_LOAD_FPU_REG_P(i) | |
421 && df_regs_ever_live_p (i) | |
422 && ! call_used_regs[i]) | |
423 { | |
424 gcc_assert (LOAD_FPU_REG_P(via_ac)); | |
425 | |
426 fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]); | |
427 fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]); | |
428 } | |
429 } | |
430 | |
431 for (i=7; i >= 0; i--) | |
432 if (df_regs_ever_live_p (i) && !call_used_regs[i]) | |
433 fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]); | |
434 | |
435 if (fsize) | |
436 fprintf((stream), "\tadd $%#" HOST_WIDE_INT_PRINT "o, sp\n", | |
437 (fsize)&0xffff); | |
438 } | |
439 | |
440 fprintf (stream, "\trts pc\n"); | |
441 fprintf (stream, "\t;/* end of epilogue*/\n\n\n"); | |
442 } | |
443 | |
444 /* Return the best assembler insn template | |
445 for moving operands[1] into operands[0] as a fullword. */ | |
446 static const char * | |
447 singlemove_string (rtx *operands) | |
448 { | |
449 if (operands[1] != const0_rtx) | |
450 return "mov %1,%0"; | |
451 | |
452 return "clr %0"; | |
453 } | |
454 | |
455 | |
456 /* Output assembler code to perform a doubleword move insn | |
457 with operands OPERANDS. */ | |
458 | |
459 const char * | |
460 output_move_double (rtx *operands) | |
461 { | |
462 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; | |
463 rtx latehalf[2]; | |
464 rtx addreg0 = 0, addreg1 = 0; | |
465 | |
466 /* First classify both operands. */ | |
467 | |
468 if (REG_P (operands[0])) | |
469 optype0 = REGOP; | |
470 else if (offsettable_memref_p (operands[0])) | |
471 optype0 = OFFSOP; | |
472 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) | |
473 optype0 = POPOP; | |
474 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) | |
475 optype0 = PUSHOP; | |
476 else if (GET_CODE (operands[0]) == MEM) | |
477 optype0 = MEMOP; | |
478 else | |
479 optype0 = RNDOP; | |
480 | |
481 if (REG_P (operands[1])) | |
482 optype1 = REGOP; | |
483 else if (CONSTANT_P (operands[1]) | |
484 #if 0 | |
485 || GET_CODE (operands[1]) == CONST_DOUBLE | |
486 #endif | |
487 ) | |
488 optype1 = CNSTOP; | |
489 else if (offsettable_memref_p (operands[1])) | |
490 optype1 = OFFSOP; | |
491 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) | |
492 optype1 = POPOP; | |
493 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) | |
494 optype1 = PUSHOP; | |
495 else if (GET_CODE (operands[1]) == MEM) | |
496 optype1 = MEMOP; | |
497 else | |
498 optype1 = RNDOP; | |
499 | |
500 /* Check for the cases that the operand constraints are not | |
501 supposed to allow to happen. Abort if we get one, | |
502 because generating code for these cases is painful. */ | |
503 | |
504 gcc_assert (optype0 != RNDOP && optype1 != RNDOP); | |
505 | |
506 /* If one operand is decrementing and one is incrementing | |
507 decrement the former register explicitly | |
508 and change that operand into ordinary indexing. */ | |
509 | |
510 if (optype0 == PUSHOP && optype1 == POPOP) | |
511 { | |
512 operands[0] = XEXP (XEXP (operands[0], 0), 0); | |
513 output_asm_insn ("sub $4,%0", operands); | |
514 operands[0] = gen_rtx_MEM (SImode, operands[0]); | |
515 optype0 = OFFSOP; | |
516 } | |
517 if (optype0 == POPOP && optype1 == PUSHOP) | |
518 { | |
519 operands[1] = XEXP (XEXP (operands[1], 0), 0); | |
520 output_asm_insn ("sub $4,%1", operands); | |
521 operands[1] = gen_rtx_MEM (SImode, operands[1]); | |
522 optype1 = OFFSOP; | |
523 } | |
524 | |
525 /* If an operand is an unoffsettable memory ref, find a register | |
526 we can increment temporarily to make it refer to the second word. */ | |
527 | |
528 if (optype0 == MEMOP) | |
529 addreg0 = find_addr_reg (XEXP (operands[0], 0)); | |
530 | |
531 if (optype1 == MEMOP) | |
532 addreg1 = find_addr_reg (XEXP (operands[1], 0)); | |
533 | |
534 /* Ok, we can do one word at a time. | |
535 Normally we do the low-numbered word first, | |
536 but if either operand is autodecrementing then we | |
537 do the high-numbered word first. | |
538 | |
539 In either case, set up in LATEHALF the operands to use | |
540 for the high-numbered word and in some cases alter the | |
541 operands in OPERANDS to be suitable for the low-numbered word. */ | |
542 | |
543 if (optype0 == REGOP) | |
544 latehalf[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1); | |
545 else if (optype0 == OFFSOP) | |
546 latehalf[0] = adjust_address (operands[0], HImode, 2); | |
547 else | |
548 latehalf[0] = operands[0]; | |
549 | |
550 if (optype1 == REGOP) | |
551 latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1); | |
552 else if (optype1 == OFFSOP) | |
553 latehalf[1] = adjust_address (operands[1], HImode, 2); | |
554 else if (optype1 == CNSTOP) | |
555 { | |
556 if (CONSTANT_P (operands[1])) | |
557 { | |
558 /* now the mess begins, high word is in lower word??? | |
559 | |
560 that's what ashc makes me think, but I don't remember :-( */ | |
561 latehalf[1] = GEN_INT (INTVAL(operands[1]) >> 16); | |
562 operands[1] = GEN_INT (INTVAL(operands[1]) & 0xff); | |
563 } | |
564 else | |
565 /* immediate 32-bit values not allowed */ | |
566 gcc_assert (GET_CODE (operands[1]) != CONST_DOUBLE); | |
567 } | |
568 else | |
569 latehalf[1] = operands[1]; | |
570 | |
571 /* If insn is effectively movd N(sp),-(sp) then we will do the | |
572 high word first. We should use the adjusted operand 1 (which is N+4(sp)) | |
573 for the low word as well, to compensate for the first decrement of sp. */ | |
574 if (optype0 == PUSHOP | |
575 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM | |
576 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) | |
577 operands[1] = latehalf[1]; | |
578 | |
579 /* If one or both operands autodecrementing, | |
580 do the two words, high-numbered first. */ | |
581 | |
582 /* Likewise, the first move would clobber the source of the second one, | |
583 do them in the other order. This happens only for registers; | |
584 such overlap can't happen in memory unless the user explicitly | |
585 sets it up, and that is an undefined circumstance. */ | |
586 | |
587 if (optype0 == PUSHOP || optype1 == PUSHOP | |
588 || (optype0 == REGOP && optype1 == REGOP | |
589 && REGNO (operands[0]) == REGNO (latehalf[1]))) | |
590 { | |
591 /* Make any unoffsettable addresses point at high-numbered word. */ | |
592 if (addreg0) | |
593 output_asm_insn ("add $2,%0", &addreg0); | |
594 if (addreg1) | |
595 output_asm_insn ("add $2,%0", &addreg1); | |
596 | |
597 /* Do that word. */ | |
598 output_asm_insn (singlemove_string (latehalf), latehalf); | |
599 | |
600 /* Undo the adds we just did. */ | |
601 if (addreg0) | |
602 output_asm_insn ("sub $2,%0", &addreg0); | |
603 if (addreg1) | |
604 output_asm_insn ("sub $2,%0", &addreg1); | |
605 | |
606 /* Do low-numbered word. */ | |
607 return singlemove_string (operands); | |
608 } | |
609 | |
610 /* Normal case: do the two words, low-numbered first. */ | |
611 | |
612 output_asm_insn (singlemove_string (operands), operands); | |
613 | |
614 /* Make any unoffsettable addresses point at high-numbered word. */ | |
615 if (addreg0) | |
616 output_asm_insn ("add $2,%0", &addreg0); | |
617 if (addreg1) | |
618 output_asm_insn ("add $2,%0", &addreg1); | |
619 | |
620 /* Do that word. */ | |
621 output_asm_insn (singlemove_string (latehalf), latehalf); | |
622 | |
623 /* Undo the adds we just did. */ | |
624 if (addreg0) | |
625 output_asm_insn ("sub $2,%0", &addreg0); | |
626 if (addreg1) | |
627 output_asm_insn ("sub $2,%0", &addreg1); | |
628 | |
629 return ""; | |
630 } | |
631 /* Output assembler code to perform a quadword move insn | |
632 with operands OPERANDS. */ | |
633 | |
634 const char * | |
635 output_move_quad (rtx *operands) | |
636 { | |
637 enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; | |
638 rtx latehalf[2]; | |
639 rtx addreg0 = 0, addreg1 = 0; | |
640 | |
641 output_asm_insn(";/* movdi/df: %1 -> %0 */", operands); | |
642 | |
643 if (REG_P (operands[0])) | |
644 optype0 = REGOP; | |
645 else if (offsettable_memref_p (operands[0])) | |
646 optype0 = OFFSOP; | |
647 else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC) | |
648 optype0 = POPOP; | |
649 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) | |
650 optype0 = PUSHOP; | |
651 else if (GET_CODE (operands[0]) == MEM) | |
652 optype0 = MEMOP; | |
653 else | |
654 optype0 = RNDOP; | |
655 | |
656 if (REG_P (operands[1])) | |
657 optype1 = REGOP; | |
658 else if (CONSTANT_P (operands[1]) | |
659 || GET_CODE (operands[1]) == CONST_DOUBLE) | |
660 optype1 = CNSTOP; | |
661 else if (offsettable_memref_p (operands[1])) | |
662 optype1 = OFFSOP; | |
663 else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC) | |
664 optype1 = POPOP; | |
665 else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) | |
666 optype1 = PUSHOP; | |
667 else if (GET_CODE (operands[1]) == MEM) | |
668 optype1 = MEMOP; | |
669 else | |
670 optype1 = RNDOP; | |
671 | |
672 /* Check for the cases that the operand constraints are not | |
673 supposed to allow to happen. Abort if we get one, | |
674 because generating code for these cases is painful. */ | |
675 | |
676 gcc_assert (optype0 != RNDOP && optype1 != RNDOP); | |
677 | |
678 /* check if we move a CPU reg to an FPU reg, or vice versa! */ | |
679 if (optype0 == REGOP && optype1 == REGOP) | |
680 /* bogus - 64 bit cannot reside in CPU! */ | |
681 gcc_assert (!CPU_REG_P(REGNO(operands[0])) | |
682 && !CPU_REG_P (REGNO(operands[1]))); | |
683 | |
684 if (optype0 == REGOP || optype1 == REGOP) | |
685 { | |
686 /* check for use of clrd???? | |
687 if you ever allow ac4 and ac5 (now we require secondary load) | |
688 you must check whether | |
689 you want to load into them or store from them - | |
690 then dump ac0 into $help$ movce ac4/5 to ac0, do the | |
691 store from ac0, and restore ac0 - if you can find | |
692 an unused ac[0-3], use that and you save a store and a load!*/ | |
693 | |
694 if (FPU_REG_P(REGNO(operands[0]))) | |
695 { | |
696 if (GET_CODE(operands[1]) == CONST_DOUBLE) | |
697 { | |
698 REAL_VALUE_TYPE r; | |
699 REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); | |
700 | |
701 if (REAL_VALUES_EQUAL (r, dconst0)) | |
702 return "{clrd|clrf} %0"; | |
703 } | |
704 | |
705 return "{ldd|movf} %1, %0"; | |
706 } | |
707 | |
708 if (FPU_REG_P(REGNO(operands[1]))) | |
709 return "{std|movf} %1, %0"; | |
710 } | |
711 | |
712 /* If one operand is decrementing and one is incrementing | |
713 decrement the former register explicitly | |
714 and change that operand into ordinary indexing. */ | |
715 | |
716 if (optype0 == PUSHOP && optype1 == POPOP) | |
717 { | |
718 operands[0] = XEXP (XEXP (operands[0], 0), 0); | |
719 output_asm_insn ("sub $8,%0", operands); | |
720 operands[0] = gen_rtx_MEM (DImode, operands[0]); | |
721 optype0 = OFFSOP; | |
722 } | |
723 if (optype0 == POPOP && optype1 == PUSHOP) | |
724 { | |
725 operands[1] = XEXP (XEXP (operands[1], 0), 0); | |
726 output_asm_insn ("sub $8,%1", operands); | |
727 operands[1] = gen_rtx_MEM (SImode, operands[1]); | |
728 optype1 = OFFSOP; | |
729 } | |
730 | |
731 /* If an operand is an unoffsettable memory ref, find a register | |
732 we can increment temporarily to make it refer to the second word. */ | |
733 | |
734 if (optype0 == MEMOP) | |
735 addreg0 = find_addr_reg (XEXP (operands[0], 0)); | |
736 | |
737 if (optype1 == MEMOP) | |
738 addreg1 = find_addr_reg (XEXP (operands[1], 0)); | |
739 | |
740 /* Ok, we can do one word at a time. | |
741 Normally we do the low-numbered word first, | |
742 but if either operand is autodecrementing then we | |
743 do the high-numbered word first. | |
744 | |
745 In either case, set up in LATEHALF the operands to use | |
746 for the high-numbered word and in some cases alter the | |
747 operands in OPERANDS to be suitable for the low-numbered word. */ | |
748 | |
749 if (optype0 == REGOP) | |
750 latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2); | |
751 else if (optype0 == OFFSOP) | |
752 latehalf[0] = adjust_address (operands[0], SImode, 4); | |
753 else | |
754 latehalf[0] = operands[0]; | |
755 | |
756 if (optype1 == REGOP) | |
757 latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2); | |
758 else if (optype1 == OFFSOP) | |
759 latehalf[1] = adjust_address (operands[1], SImode, 4); | |
760 else if (optype1 == CNSTOP) | |
761 { | |
762 if (GET_CODE (operands[1]) == CONST_DOUBLE) | |
763 { | |
764 REAL_VALUE_TYPE r; | |
765 long dval[2]; | |
766 REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); | |
767 REAL_VALUE_TO_TARGET_DOUBLE (r, dval); | |
768 latehalf[1] = GEN_INT (dval[1]); | |
769 operands[1] = GEN_INT (dval[0]); | |
770 } | |
771 else if (GET_CODE(operands[1]) == CONST_INT) | |
772 { | |
773 latehalf[1] = const0_rtx; | |
774 } | |
775 else | |
776 gcc_unreachable (); | |
777 } | |
778 else | |
779 latehalf[1] = operands[1]; | |
780 | |
781 /* If insn is effectively movd N(sp),-(sp) then we will do the | |
782 high word first. We should use the adjusted operand 1 (which is N+4(sp)) | |
783 for the low word as well, to compensate for the first decrement of sp. */ | |
784 if (optype0 == PUSHOP | |
785 && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM | |
786 && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) | |
787 operands[1] = latehalf[1]; | |
788 | |
789 /* If one or both operands autodecrementing, | |
790 do the two words, high-numbered first. */ | |
791 | |
792 /* Likewise, the first move would clobber the source of the second one, | |
793 do them in the other order. This happens only for registers; | |
794 such overlap can't happen in memory unless the user explicitly | |
795 sets it up, and that is an undefined circumstance. */ | |
796 | |
797 if (optype0 == PUSHOP || optype1 == PUSHOP | |
798 || (optype0 == REGOP && optype1 == REGOP | |
799 && REGNO (operands[0]) == REGNO (latehalf[1]))) | |
800 { | |
801 /* Make any unoffsettable addresses point at high-numbered word. */ | |
802 if (addreg0) | |
803 output_asm_insn ("add $4,%0", &addreg0); | |
804 if (addreg1) | |
805 output_asm_insn ("add $4,%0", &addreg1); | |
806 | |
807 /* Do that word. */ | |
808 output_asm_insn(output_move_double(latehalf), latehalf); | |
809 | |
810 /* Undo the adds we just did. */ | |
811 if (addreg0) | |
812 output_asm_insn ("sub $4,%0", &addreg0); | |
813 if (addreg1) | |
814 output_asm_insn ("sub $4,%0", &addreg1); | |
815 | |
816 /* Do low-numbered word. */ | |
817 return output_move_double (operands); | |
818 } | |
819 | |
820 /* Normal case: do the two words, low-numbered first. */ | |
821 | |
822 output_asm_insn (output_move_double (operands), operands); | |
823 | |
824 /* Make any unoffsettable addresses point at high-numbered word. */ | |
825 if (addreg0) | |
826 output_asm_insn ("add $4,%0", &addreg0); | |
827 if (addreg1) | |
828 output_asm_insn ("add $4,%0", &addreg1); | |
829 | |
830 /* Do that word. */ | |
831 output_asm_insn (output_move_double (latehalf), latehalf); | |
832 | |
833 /* Undo the adds we just did. */ | |
834 if (addreg0) | |
835 output_asm_insn ("sub $4,%0", &addreg0); | |
836 if (addreg1) | |
837 output_asm_insn ("sub $4,%0", &addreg1); | |
838 | |
839 return ""; | |
840 } | |
841 | |
842 | |
843 /* Return a REG that occurs in ADDR with coefficient 1. | |
844 ADDR can be effectively incremented by incrementing REG. */ | |
845 | |
846 static rtx | |
847 find_addr_reg (rtx addr) | |
848 { | |
849 while (GET_CODE (addr) == PLUS) | |
850 { | |
851 if (GET_CODE (XEXP (addr, 0)) == REG) | |
852 addr = XEXP (addr, 0); | |
853 if (GET_CODE (XEXP (addr, 1)) == REG) | |
854 addr = XEXP (addr, 1); | |
855 if (CONSTANT_P (XEXP (addr, 0))) | |
856 addr = XEXP (addr, 1); | |
857 if (CONSTANT_P (XEXP (addr, 1))) | |
858 addr = XEXP (addr, 0); | |
859 } | |
860 if (GET_CODE (addr) == REG) | |
861 return addr; | |
862 return 0; | |
863 } | |
864 | |
865 /* Output an ascii string. */ | |
866 void | |
867 output_ascii (FILE *file, const char *p, int size) | |
868 { | |
869 int i; | |
870 | |
871 /* This used to output .byte "string", which doesn't work with the UNIX | |
872 assembler and I think not with DEC ones either. */ | |
873 fprintf (file, "\t.byte "); | |
874 | |
875 for (i = 0; i < size; i++) | |
876 { | |
877 register int c = p[i]; | |
878 if (c < 0) | |
879 c += 256; | |
880 fprintf (file, "%#o", c); | |
881 if (i < size - 1) | |
882 putc (',', file); | |
883 } | |
884 putc ('\n', file); | |
885 } | |
886 | |
887 | |
888 /* --- stole from out-vax, needs changes */ | |
889 | |
890 void | |
891 print_operand_address (FILE *file, register rtx addr) | |
892 { | |
893 register rtx reg1, reg2, breg, ireg; | |
894 rtx offset; | |
895 | |
896 retry: | |
897 | |
898 switch (GET_CODE (addr)) | |
899 { | |
900 case MEM: | |
901 if (TARGET_UNIX_ASM) | |
902 fprintf (file, "*"); | |
903 else | |
904 fprintf (file, "@"); | |
905 addr = XEXP (addr, 0); | |
906 goto retry; | |
907 | |
908 case REG: | |
909 fprintf (file, "(%s)", reg_names[REGNO (addr)]); | |
910 break; | |
911 | |
912 case PRE_MODIFY: | |
913 case PRE_DEC: | |
914 fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); | |
915 break; | |
916 | |
917 case POST_MODIFY: | |
918 case POST_INC: | |
919 fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); | |
920 break; | |
921 | |
922 case PLUS: | |
923 reg1 = 0; reg2 = 0; | |
924 ireg = 0; breg = 0; | |
925 offset = 0; | |
926 if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) | |
927 || GET_CODE (XEXP (addr, 0)) == MEM) | |
928 { | |
929 offset = XEXP (addr, 0); | |
930 addr = XEXP (addr, 1); | |
931 } | |
932 else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) | |
933 || GET_CODE (XEXP (addr, 1)) == MEM) | |
934 { | |
935 offset = XEXP (addr, 1); | |
936 addr = XEXP (addr, 0); | |
937 } | |
938 if (GET_CODE (addr) != PLUS) | |
939 ; | |
940 else if (GET_CODE (XEXP (addr, 0)) == MULT) | |
941 { | |
942 reg1 = XEXP (addr, 0); | |
943 addr = XEXP (addr, 1); | |
944 } | |
945 else if (GET_CODE (XEXP (addr, 1)) == MULT) | |
946 { | |
947 reg1 = XEXP (addr, 1); | |
948 addr = XEXP (addr, 0); | |
949 } | |
950 else if (GET_CODE (XEXP (addr, 0)) == REG) | |
951 { | |
952 reg1 = XEXP (addr, 0); | |
953 addr = XEXP (addr, 1); | |
954 } | |
955 else if (GET_CODE (XEXP (addr, 1)) == REG) | |
956 { | |
957 reg1 = XEXP (addr, 1); | |
958 addr = XEXP (addr, 0); | |
959 } | |
960 if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) | |
961 { | |
962 if (reg1 == 0) | |
963 reg1 = addr; | |
964 else | |
965 reg2 = addr; | |
966 addr = 0; | |
967 } | |
968 if (offset != 0) | |
969 { | |
970 gcc_assert (addr == 0); | |
971 addr = offset; | |
972 } | |
973 if (reg1 != 0 && GET_CODE (reg1) == MULT) | |
974 { | |
975 breg = reg2; | |
976 ireg = reg1; | |
977 } | |
978 else if (reg2 != 0 && GET_CODE (reg2) == MULT) | |
979 { | |
980 breg = reg1; | |
981 ireg = reg2; | |
982 } | |
983 else if (reg2 != 0 || GET_CODE (addr) == MEM) | |
984 { | |
985 breg = reg2; | |
986 ireg = reg1; | |
987 } | |
988 else | |
989 { | |
990 breg = reg1; | |
991 ireg = reg2; | |
992 } | |
993 if (addr != 0) | |
994 output_address (addr); | |
995 if (breg != 0) | |
996 { | |
997 gcc_assert (GET_CODE (breg) == REG); | |
998 fprintf (file, "(%s)", reg_names[REGNO (breg)]); | |
999 } | |
1000 if (ireg != 0) | |
1001 { | |
1002 if (GET_CODE (ireg) == MULT) | |
1003 ireg = XEXP (ireg, 0); | |
1004 gcc_assert (GET_CODE (ireg) == REG); | |
1005 gcc_unreachable(); /* ??? */ | |
1006 fprintf (file, "[%s]", reg_names[REGNO (ireg)]); | |
1007 } | |
1008 break; | |
1009 | |
1010 default: | |
1011 output_addr_const_pdp11 (file, addr); | |
1012 } | |
1013 } | |
1014 | |
1015 /* Target hook to assemble integer objects. We need to use the | |
1016 pdp-specific version of output_addr_const. */ | |
1017 | |
1018 static bool | |
1019 pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p) | |
1020 { | |
1021 if (aligned_p) | |
1022 switch (size) | |
1023 { | |
1024 case 1: | |
1025 fprintf (asm_out_file, "\t.byte\t"); | |
1026 output_addr_const_pdp11 (asm_out_file, x); | |
1027 fprintf (asm_out_file, " /* char */\n"); | |
1028 return true; | |
1029 | |
1030 case 2: | |
1031 fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t"); | |
1032 output_addr_const_pdp11 (asm_out_file, x); | |
1033 fprintf (asm_out_file, " /* short */\n"); | |
1034 return true; | |
1035 } | |
1036 return default_assemble_integer (x, size, aligned_p); | |
1037 } | |
1038 | |
1039 | |
1040 /* register move costs, indexed by regs */ | |
1041 | |
1042 static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] = | |
1043 { | |
1044 /* NO MUL GEN LFPU NLFPU FPU ALL */ | |
1045 | |
1046 /* NO */ { 0, 0, 0, 0, 0, 0, 0}, | |
1047 /* MUL */ { 0, 2, 2, 10, 22, 22, 22}, | |
1048 /* GEN */ { 0, 2, 2, 10, 22, 22, 22}, | |
1049 /* LFPU */ { 0, 10, 10, 2, 2, 2, 10}, | |
1050 /* NLFPU */ { 0, 22, 22, 2, 2, 2, 22}, | |
1051 /* FPU */ { 0, 22, 22, 2, 2, 2, 22}, | |
1052 /* ALL */ { 0, 22, 22, 10, 22, 22, 22} | |
1053 } ; | |
1054 | |
1055 | |
1056 /* -- note that some moves are tremendously expensive, | |
1057 because they require lots of tricks! do we have to | |
1058 charge the costs incurred by secondary reload class | |
1059 -- as we do here with 22 -- or not ? */ | |
1060 | |
1061 int | |
1062 register_move_cost(enum reg_class c1, enum reg_class c2) | |
1063 { | |
1064 return move_costs[(int)c1][(int)c2]; | |
1065 } | |
1066 | |
1067 static bool | |
1068 pdp11_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total, | |
1069 bool speed ATTRIBUTE_UNUSED) | |
1070 { | |
1071 switch (code) | |
1072 { | |
1073 case CONST_INT: | |
1074 if (INTVAL (x) == 0 || INTVAL (x) == -1 || INTVAL (x) == 1) | |
1075 { | |
1076 *total = 0; | |
1077 return true; | |
1078 } | |
1079 /* FALLTHRU */ | |
1080 | |
1081 case CONST: | |
1082 case LABEL_REF: | |
1083 case SYMBOL_REF: | |
1084 /* Twice as expensive as REG. */ | |
1085 *total = 2; | |
1086 return true; | |
1087 | |
1088 case CONST_DOUBLE: | |
1089 /* Twice (or 4 times) as expensive as 16 bit. */ | |
1090 *total = 4; | |
1091 return true; | |
1092 | |
1093 case MULT: | |
1094 /* ??? There is something wrong in MULT because MULT is not | |
1095 as cheap as total = 2 even if we can shift! */ | |
1096 /* If optimizing for size make mult etc cheap, but not 1, so when | |
1097 in doubt the faster insn is chosen. */ | |
1098 if (optimize_size) | |
1099 *total = COSTS_N_INSNS (2); | |
1100 else | |
1101 *total = COSTS_N_INSNS (11); | |
1102 return false; | |
1103 | |
1104 case DIV: | |
1105 if (optimize_size) | |
1106 *total = COSTS_N_INSNS (2); | |
1107 else | |
1108 *total = COSTS_N_INSNS (25); | |
1109 return false; | |
1110 | |
1111 case MOD: | |
1112 if (optimize_size) | |
1113 *total = COSTS_N_INSNS (2); | |
1114 else | |
1115 *total = COSTS_N_INSNS (26); | |
1116 return false; | |
1117 | |
1118 case ABS: | |
1119 /* Equivalent to length, so same for optimize_size. */ | |
1120 *total = COSTS_N_INSNS (3); | |
1121 return false; | |
1122 | |
1123 case ZERO_EXTEND: | |
1124 /* Only used for qi->hi. */ | |
1125 *total = COSTS_N_INSNS (1); | |
1126 return false; | |
1127 | |
1128 case SIGN_EXTEND: | |
1129 if (GET_MODE (x) == HImode) | |
1130 *total = COSTS_N_INSNS (1); | |
1131 else if (GET_MODE (x) == SImode) | |
1132 *total = COSTS_N_INSNS (6); | |
1133 else | |
1134 *total = COSTS_N_INSNS (2); | |
1135 return false; | |
1136 | |
1137 case ASHIFT: | |
1138 case LSHIFTRT: | |
1139 case ASHIFTRT: | |
1140 if (optimize_size) | |
1141 *total = COSTS_N_INSNS (1); | |
1142 else if (GET_MODE (x) == QImode) | |
1143 { | |
1144 if (GET_CODE (XEXP (x, 1)) != CONST_INT) | |
1145 *total = COSTS_N_INSNS (8); /* worst case */ | |
1146 else | |
1147 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))); | |
1148 } | |
1149 else if (GET_MODE (x) == HImode) | |
1150 { | |
1151 if (GET_CODE (XEXP (x, 1)) == CONST_INT) | |
1152 { | |
1153 if (abs (INTVAL (XEXP (x, 1))) == 1) | |
1154 *total = COSTS_N_INSNS (1); | |
1155 else | |
1156 *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1))); | |
1157 } | |
1158 else | |
1159 *total = COSTS_N_INSNS (10); /* worst case */ | |
1160 } | |
1161 else if (GET_MODE (x) == SImode) | |
1162 { | |
1163 if (GET_CODE (XEXP (x, 1)) == CONST_INT) | |
1164 *total = COSTS_N_INSNS (2.5 + 0.5 * INTVAL (XEXP (x, 1))); | |
1165 else /* worst case */ | |
1166 *total = COSTS_N_INSNS (18); | |
1167 } | |
1168 return false; | |
1169 | |
1170 default: | |
1171 return false; | |
1172 } | |
1173 } | |
1174 | |
1175 const char * | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1176 output_jump (enum rtx_code code, int inv, int length) |
0 | 1177 { |
1178 static int x = 0; | |
1179 | |
1180 static char buf[1000]; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1181 const char *pos, *neg; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1182 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1183 switch (code) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1184 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1185 case EQ: pos = "beq", neg = "bne"; break; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1186 case NE: pos = "bne", neg = "beq"; break; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1187 case GT: pos = "bgt", neg = "ble"; break; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1188 case GTU: pos = "bhi", neg = "blos"; break; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1189 case LT: pos = "blt", neg = "bge"; break; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1190 case LTU: pos = "blo", neg = "bhis"; break; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1191 case GE: pos = "bge", neg = "blt"; break; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1192 case GEU: pos = "bhis", neg = "blo"; break; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1193 case LE: pos = "ble", neg = "bgt"; break; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1194 case LEU: pos = "blos", neg = "bhi"; break; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1195 default: gcc_unreachable (); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1196 } |
0 | 1197 |
1198 #if 0 | |
1199 /* currently we don't need this, because the tstdf and cmpdf | |
1200 copy the condition code immediately, and other float operations are not | |
1201 yet recognized as changing the FCC - if so, then the length-cost of all | |
1202 jump insns increases by one, because we have to potentially copy the | |
1203 FCC! */ | |
1204 if (cc_status.flags & CC_IN_FPU) | |
1205 output_asm_insn("cfcc", NULL); | |
1206 #endif | |
1207 | |
1208 switch (length) | |
1209 { | |
1210 case 1: | |
1211 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1212 sprintf(buf, "%s %%l1", inv ? neg : pos); |
0 | 1213 |
1214 return buf; | |
1215 | |
1216 case 3: | |
1217 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1218 sprintf(buf, "%s JMP_%d\n\tjmp %%l1\nJMP_%d:", inv ? pos : neg, x, x); |
0 | 1219 |
1220 x++; | |
1221 | |
1222 return buf; | |
1223 | |
1224 default: | |
1225 | |
1226 gcc_unreachable (); | |
1227 } | |
1228 | |
1229 } | |
1230 | |
1231 void | |
1232 notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED) | |
1233 { | |
1234 if (GET_CODE (SET_DEST (exp)) == CC0) | |
1235 { | |
1236 cc_status.flags = 0; | |
1237 cc_status.value1 = SET_DEST (exp); | |
1238 cc_status.value2 = SET_SRC (exp); | |
1239 | |
1240 /* | |
1241 if (GET_MODE(SET_SRC(exp)) == DFmode) | |
1242 cc_status.flags |= CC_IN_FPU; | |
1243 */ | |
1244 } | |
1245 else if ((GET_CODE (SET_DEST (exp)) == REG | |
1246 || GET_CODE (SET_DEST (exp)) == MEM) | |
1247 && GET_CODE (SET_SRC (exp)) != PC | |
1248 && (GET_MODE (SET_DEST(exp)) == HImode | |
1249 || GET_MODE (SET_DEST(exp)) == QImode) | |
1250 && (GET_CODE (SET_SRC(exp)) == PLUS | |
1251 || GET_CODE (SET_SRC(exp)) == MINUS | |
1252 || GET_CODE (SET_SRC(exp)) == AND | |
1253 || GET_CODE (SET_SRC(exp)) == IOR | |
1254 || GET_CODE (SET_SRC(exp)) == XOR | |
1255 || GET_CODE (SET_SRC(exp)) == NOT | |
1256 || GET_CODE (SET_SRC(exp)) == NEG | |
1257 || GET_CODE (SET_SRC(exp)) == REG | |
1258 || GET_CODE (SET_SRC(exp)) == MEM)) | |
1259 { | |
1260 cc_status.flags = 0; | |
1261 cc_status.value1 = SET_SRC (exp); | |
1262 cc_status.value2 = SET_DEST (exp); | |
1263 | |
1264 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG | |
1265 && cc_status.value2 | |
1266 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) | |
1267 cc_status.value2 = 0; | |
1268 if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM | |
1269 && cc_status.value2 | |
1270 && GET_CODE (cc_status.value2) == MEM) | |
1271 cc_status.value2 = 0; | |
1272 } | |
1273 else if (GET_CODE (SET_SRC (exp)) == CALL) | |
1274 { | |
1275 CC_STATUS_INIT; | |
1276 } | |
1277 else if (GET_CODE (SET_DEST (exp)) == REG) | |
1278 /* what's this ? */ | |
1279 { | |
1280 if ((cc_status.value1 | |
1281 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))) | |
1282 cc_status.value1 = 0; | |
1283 if ((cc_status.value2 | |
1284 && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))) | |
1285 cc_status.value2 = 0; | |
1286 } | |
1287 else if (SET_DEST(exp) == pc_rtx) | |
1288 { | |
1289 /* jump */ | |
1290 } | |
1291 else /* if (GET_CODE (SET_DEST (exp)) == MEM) */ | |
1292 { | |
1293 /* the last else is a bit paranoiac, but since nearly all instructions | |
1294 play with condition codes, it's reasonable! */ | |
1295 | |
1296 CC_STATUS_INIT; /* paranoia*/ | |
1297 } | |
1298 } | |
1299 | |
1300 | |
1301 int | |
1302 simple_memory_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) | |
1303 { | |
1304 rtx addr; | |
1305 | |
1306 /* Eliminate non-memory operations */ | |
1307 if (GET_CODE (op) != MEM) | |
1308 return FALSE; | |
1309 | |
1310 #if 0 | |
1311 /* dword operations really put out 2 instructions, so eliminate them. */ | |
1312 if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4)) | |
1313 return FALSE; | |
1314 #endif | |
1315 | |
1316 /* Decode the address now. */ | |
1317 | |
1318 indirection: | |
1319 | |
1320 addr = XEXP (op, 0); | |
1321 | |
1322 switch (GET_CODE (addr)) | |
1323 { | |
1324 case REG: | |
1325 /* (R0) - no extra cost */ | |
1326 return 1; | |
1327 | |
1328 case PRE_DEC: | |
1329 case POST_INC: | |
1330 /* -(R0), (R0)+ - cheap! */ | |
1331 return 0; | |
1332 | |
1333 case MEM: | |
1334 /* cheap - is encoded in addressing mode info! | |
1335 | |
1336 -- except for @(R0), which has to be @0(R0) !!! */ | |
1337 | |
1338 if (GET_CODE (XEXP (addr, 0)) == REG) | |
1339 return 0; | |
1340 | |
1341 op=addr; | |
1342 goto indirection; | |
1343 | |
1344 case CONST_INT: | |
1345 case LABEL_REF: | |
1346 case CONST: | |
1347 case SYMBOL_REF: | |
1348 /* @#address - extra cost */ | |
1349 return 0; | |
1350 | |
1351 case PLUS: | |
1352 /* X(R0) - extra cost */ | |
1353 return 0; | |
1354 | |
1355 default: | |
1356 break; | |
1357 } | |
1358 | |
1359 return FALSE; | |
1360 } | |
1361 | |
1362 | |
1363 /* | |
1364 * output a block move: | |
1365 * | |
1366 * operands[0] ... to | |
1367 * operands[1] ... from | |
1368 * operands[2] ... length | |
1369 * operands[3] ... alignment | |
1370 * operands[4] ... scratch register | |
1371 */ | |
1372 | |
1373 | |
1374 const char * | |
1375 output_block_move(rtx *operands) | |
1376 { | |
1377 static int count = 0; | |
1378 char buf[200]; | |
1379 | |
1380 if (GET_CODE(operands[2]) == CONST_INT | |
1381 && ! optimize_size) | |
1382 { | |
1383 if (INTVAL(operands[2]) < 16 | |
1384 && INTVAL(operands[3]) == 1) | |
1385 { | |
1386 register int i; | |
1387 | |
1388 for (i = 1; i <= INTVAL(operands[2]); i++) | |
1389 output_asm_insn("movb (%1)+, (%0)+", operands); | |
1390 | |
1391 return ""; | |
1392 } | |
1393 else if (INTVAL(operands[2]) < 32) | |
1394 { | |
1395 register int i; | |
1396 | |
1397 for (i = 1; i <= INTVAL(operands[2])/2; i++) | |
1398 output_asm_insn("mov (%1)+, (%0)+", operands); | |
1399 | |
1400 /* may I assume that moved quantity is | |
1401 multiple of alignment ??? | |
1402 | |
1403 I HOPE SO ! | |
1404 */ | |
1405 | |
1406 return ""; | |
1407 } | |
1408 | |
1409 | |
1410 /* can do other clever things, maybe... */ | |
1411 } | |
1412 | |
1413 if (CONSTANT_P(operands[2]) ) | |
1414 { | |
1415 /* just move count to scratch */ | |
1416 output_asm_insn("mov %2, %4", operands); | |
1417 } | |
1418 else | |
1419 { | |
1420 /* just clobber the register */ | |
1421 operands[4] = operands[2]; | |
1422 } | |
1423 | |
1424 | |
1425 /* switch over alignment */ | |
1426 switch (INTVAL(operands[3])) | |
1427 { | |
1428 case 1: | |
1429 | |
1430 /* | |
1431 x: | |
1432 movb (%1)+, (%0)+ | |
1433 | |
1434 if (TARGET_45) | |
1435 sob %4,x | |
1436 else | |
1437 dec %4 | |
1438 bgt x | |
1439 | |
1440 */ | |
1441 | |
1442 sprintf(buf, "\nmovestrhi%d:", count); | |
1443 output_asm_insn(buf, NULL); | |
1444 | |
1445 output_asm_insn("movb (%1)+, (%0)+", operands); | |
1446 | |
1447 if (TARGET_45) | |
1448 { | |
1449 sprintf(buf, "sob %%4, movestrhi%d", count); | |
1450 output_asm_insn(buf, operands); | |
1451 } | |
1452 else | |
1453 { | |
1454 output_asm_insn("dec %4", operands); | |
1455 | |
1456 sprintf(buf, "bgt movestrhi%d", count); | |
1457 output_asm_insn(buf, NULL); | |
1458 } | |
1459 | |
1460 count ++; | |
1461 break; | |
1462 | |
1463 case 2: | |
1464 | |
1465 /* | |
1466 asr %4 | |
1467 | |
1468 x: | |
1469 | |
1470 mov (%1)+, (%0)+ | |
1471 | |
1472 if (TARGET_45) | |
1473 sob %4, x | |
1474 else | |
1475 dec %4 | |
1476 bgt x | |
1477 */ | |
1478 | |
1479 generate_compact_code: | |
1480 | |
1481 output_asm_insn("asr %4", operands); | |
1482 | |
1483 sprintf(buf, "\nmovestrhi%d:", count); | |
1484 output_asm_insn(buf, NULL); | |
1485 | |
1486 output_asm_insn("mov (%1)+, (%0)+", operands); | |
1487 | |
1488 if (TARGET_45) | |
1489 { | |
1490 sprintf(buf, "sob %%4, movestrhi%d", count); | |
1491 output_asm_insn(buf, operands); | |
1492 } | |
1493 else | |
1494 { | |
1495 output_asm_insn("dec %4", operands); | |
1496 | |
1497 sprintf(buf, "bgt movestrhi%d", count); | |
1498 output_asm_insn(buf, NULL); | |
1499 } | |
1500 | |
1501 count ++; | |
1502 break; | |
1503 | |
1504 case 4: | |
1505 | |
1506 /* | |
1507 | |
1508 asr %4 | |
1509 asr %4 | |
1510 | |
1511 x: | |
1512 | |
1513 mov (%1)+, (%0)+ | |
1514 mov (%1)+, (%0)+ | |
1515 | |
1516 if (TARGET_45) | |
1517 sob %4, x | |
1518 else | |
1519 dec %4 | |
1520 bgt x | |
1521 */ | |
1522 | |
1523 if (optimize_size) | |
1524 goto generate_compact_code; | |
1525 | |
1526 output_asm_insn("asr %4", operands); | |
1527 output_asm_insn("asr %4", operands); | |
1528 | |
1529 sprintf(buf, "\nmovestrhi%d:", count); | |
1530 output_asm_insn(buf, NULL); | |
1531 | |
1532 output_asm_insn("mov (%1)+, (%0)+", operands); | |
1533 output_asm_insn("mov (%1)+, (%0)+", operands); | |
1534 | |
1535 if (TARGET_45) | |
1536 { | |
1537 sprintf(buf, "sob %%4, movestrhi%d", count); | |
1538 output_asm_insn(buf, operands); | |
1539 } | |
1540 else | |
1541 { | |
1542 output_asm_insn("dec %4", operands); | |
1543 | |
1544 sprintf(buf, "bgt movestrhi%d", count); | |
1545 output_asm_insn(buf, NULL); | |
1546 } | |
1547 | |
1548 count ++; | |
1549 break; | |
1550 | |
1551 default: | |
1552 | |
1553 /* | |
1554 | |
1555 asr %4 | |
1556 asr %4 | |
1557 asr %4 | |
1558 | |
1559 x: | |
1560 | |
1561 mov (%1)+, (%0)+ | |
1562 mov (%1)+, (%0)+ | |
1563 mov (%1)+, (%0)+ | |
1564 mov (%1)+, (%0)+ | |
1565 | |
1566 if (TARGET_45) | |
1567 sob %4, x | |
1568 else | |
1569 dec %4 | |
1570 bgt x | |
1571 */ | |
1572 | |
1573 | |
1574 if (optimize_size) | |
1575 goto generate_compact_code; | |
1576 | |
1577 output_asm_insn("asr %4", operands); | |
1578 output_asm_insn("asr %4", operands); | |
1579 output_asm_insn("asr %4", operands); | |
1580 | |
1581 sprintf(buf, "\nmovestrhi%d:", count); | |
1582 output_asm_insn(buf, NULL); | |
1583 | |
1584 output_asm_insn("mov (%1)+, (%0)+", operands); | |
1585 output_asm_insn("mov (%1)+, (%0)+", operands); | |
1586 output_asm_insn("mov (%1)+, (%0)+", operands); | |
1587 output_asm_insn("mov (%1)+, (%0)+", operands); | |
1588 | |
1589 if (TARGET_45) | |
1590 { | |
1591 sprintf(buf, "sob %%4, movestrhi%d", count); | |
1592 output_asm_insn(buf, operands); | |
1593 } | |
1594 else | |
1595 { | |
1596 output_asm_insn("dec %4", operands); | |
1597 | |
1598 sprintf(buf, "bgt movestrhi%d", count); | |
1599 output_asm_insn(buf, NULL); | |
1600 } | |
1601 | |
1602 count ++; | |
1603 break; | |
1604 | |
1605 ; | |
1606 | |
1607 } | |
1608 | |
1609 return ""; | |
1610 } | |
1611 | |
1612 /* This function checks whether a real value can be encoded as | |
1613 a literal, i.e., addressing mode 27. In that mode, real values | |
1614 are one word values, so the remaining 48 bits have to be zero. */ | |
1615 int | |
1616 legitimate_const_double_p (rtx address) | |
1617 { | |
1618 REAL_VALUE_TYPE r; | |
1619 long sval[2]; | |
1620 REAL_VALUE_FROM_CONST_DOUBLE (r, address); | |
1621 REAL_VALUE_TO_TARGET_DOUBLE (r, sval); | |
1622 if ((sval[0] & 0xffff) == 0 && sval[1] == 0) | |
1623 return 1; | |
1624 return 0; | |
1625 } | |
1626 | |
1627 /* A copy of output_addr_const modified for pdp11 expression syntax. | |
1628 output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't | |
1629 use, and for debugging output, which we don't support with this port either. | |
1630 So this copy should get called whenever needed. | |
1631 */ | |
1632 void | |
1633 output_addr_const_pdp11 (FILE *file, rtx x) | |
1634 { | |
1635 char buf[256]; | |
1636 | |
1637 restart: | |
1638 switch (GET_CODE (x)) | |
1639 { | |
1640 case PC: | |
1641 gcc_assert (flag_pic); | |
1642 putc ('.', file); | |
1643 break; | |
1644 | |
1645 case SYMBOL_REF: | |
1646 assemble_name (file, XSTR (x, 0)); | |
1647 break; | |
1648 | |
1649 case LABEL_REF: | |
1650 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); | |
1651 assemble_name (file, buf); | |
1652 break; | |
1653 | |
1654 case CODE_LABEL: | |
1655 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); | |
1656 assemble_name (file, buf); | |
1657 break; | |
1658 | |
1659 case CONST_INT: | |
1660 /* Should we check for constants which are too big? Maybe cutting | |
1661 them off to 16 bits is OK? */ | |
1662 fprintf (file, "%#ho", (unsigned short) INTVAL (x)); | |
1663 break; | |
1664 | |
1665 case CONST: | |
1666 /* This used to output parentheses around the expression, | |
1667 but that does not work on the 386 (either ATT or BSD assembler). */ | |
1668 output_addr_const_pdp11 (file, XEXP (x, 0)); | |
1669 break; | |
1670 | |
1671 case CONST_DOUBLE: | |
1672 if (GET_MODE (x) == VOIDmode) | |
1673 { | |
1674 /* We can use %o if the number is one word and positive. */ | |
1675 gcc_assert (!CONST_DOUBLE_HIGH (x)); | |
1676 fprintf (file, "%#ho", (unsigned short) CONST_DOUBLE_LOW (x)); | |
1677 } | |
1678 else | |
1679 /* We can't handle floating point constants; | |
1680 PRINT_OPERAND must handle them. */ | |
1681 output_operand_lossage ("floating constant misused"); | |
1682 break; | |
1683 | |
1684 case PLUS: | |
1685 /* Some assemblers need integer constants to appear last (e.g. masm). */ | |
1686 if (GET_CODE (XEXP (x, 0)) == CONST_INT) | |
1687 { | |
1688 output_addr_const_pdp11 (file, XEXP (x, 1)); | |
1689 if (INTVAL (XEXP (x, 0)) >= 0) | |
1690 fprintf (file, "+"); | |
1691 output_addr_const_pdp11 (file, XEXP (x, 0)); | |
1692 } | |
1693 else | |
1694 { | |
1695 output_addr_const_pdp11 (file, XEXP (x, 0)); | |
1696 if (INTVAL (XEXP (x, 1)) >= 0) | |
1697 fprintf (file, "+"); | |
1698 output_addr_const_pdp11 (file, XEXP (x, 1)); | |
1699 } | |
1700 break; | |
1701 | |
1702 case MINUS: | |
1703 /* Avoid outputting things like x-x or x+5-x, | |
1704 since some assemblers can't handle that. */ | |
1705 x = simplify_subtraction (x); | |
1706 if (GET_CODE (x) != MINUS) | |
1707 goto restart; | |
1708 | |
1709 output_addr_const_pdp11 (file, XEXP (x, 0)); | |
1710 fprintf (file, "-"); | |
1711 if (GET_CODE (XEXP (x, 1)) == CONST_INT | |
1712 && INTVAL (XEXP (x, 1)) < 0) | |
1713 { | |
1714 fprintf (file, targetm.asm_out.open_paren); | |
1715 output_addr_const_pdp11 (file, XEXP (x, 1)); | |
1716 fprintf (file, targetm.asm_out.close_paren); | |
1717 } | |
1718 else | |
1719 output_addr_const_pdp11 (file, XEXP (x, 1)); | |
1720 break; | |
1721 | |
1722 case ZERO_EXTEND: | |
1723 case SIGN_EXTEND: | |
1724 output_addr_const_pdp11 (file, XEXP (x, 0)); | |
1725 break; | |
1726 | |
1727 default: | |
1728 output_operand_lossage ("invalid expression as operand"); | |
1729 } | |
1730 } | |
1731 | |
1732 /* Worker function for TARGET_RETURN_IN_MEMORY. */ | |
1733 | |
1734 static bool | |
1735 pdp11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) | |
1736 { | |
1737 /* Should probably return DImode and DFmode in memory, lest | |
1738 we fill up all regs! | |
1739 | |
1740 have to, else we crash - exception: maybe return result in | |
1741 ac0 if DFmode and FPU present - compatibility problem with | |
1742 libraries for non-floating point.... */ | |
1743 return (TYPE_MODE (type) == DImode | |
1744 || (TYPE_MODE (type) == DFmode && ! TARGET_AC0)); | |
1745 } | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1746 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1747 /* Worker function for TARGET_TRAMPOLINE_INIT. |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1748 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1749 trampoline - how should i do it in separate i+d ? |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1750 have some allocate_trampoline magic??? |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1751 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1752 the following should work for shared I/D: |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1753 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1754 MV #STATIC, $4 0x940Y 0x0000 <- STATIC; Y = STATIC_CHAIN_REGNUM |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1755 JMP FUNCTION 0x0058 0x0000 <- FUNCTION |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1756 */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1757 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1758 static void |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1759 pdp11_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1760 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1761 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1762 rtx mem; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1763 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1764 gcc_assert (!TARGET_SPLIT); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1765 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1766 mem = adjust_address (m_tramp, HImode, 0); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1767 emit_move_insn (mem, GEN_INT (0x9400+STATIC_CHAIN_REGNUM)); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1768 mem = adjust_address (m_tramp, HImode, 2); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1769 emit_move_insn (mem, chain_value); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1770 mem = adjust_address (m_tramp, HImode, 4); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1771 emit_move_insn (mem, GEN_INT (0x0058)); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1772 emit_move_insn (mem, fnaddr); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
1773 } |