]>
Commit | Line | Data |
---|---|---|
ad082475 | 1 | /* Subroutines for insn-output.c for Clipper |
c5c76735 | 2 | Copyright (C) 1987, 88, 91, 97, 98, 1999 Free Software Foundation, Inc. |
ad082475 RS |
3 | Contributed by Holger Teutsch (holger@hotbso.rhein-main.de) |
4 | ||
5 | This file is part of GNU CC. | |
6 | ||
7 | GNU CC is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GNU CC is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GNU CC; see the file COPYING. If not, write to | |
97aadbb9 RK |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, |
20 | Boston, MA 02111-1307, USA. */ | |
ad082475 | 21 | |
ad082475 | 22 | #include "config.h" |
c5c76735 | 23 | #include "system.h" |
ad082475 RS |
24 | #include "rtl.h" |
25 | #include "regs.h" | |
26 | #include "hard-reg-set.h" | |
27 | #include "real.h" | |
28 | #include "insn-config.h" | |
29 | #include "conditions.h" | |
30 | #include "insn-flags.h" | |
31 | #include "output.h" | |
32 | #include "insn-attr.h" | |
33 | #include "tree.h" | |
34 | #include "c-tree.h" | |
49ad7cfa | 35 | #include "function.h" |
ad082475 RS |
36 | #include "expr.h" |
37 | #include "flags.h" | |
38 | #include "machmode.h" | |
39 | ||
40 | extern char regs_ever_live[]; | |
41 | ||
a3404926 | 42 | extern int frame_pointer_needed; |
ad082475 | 43 | |
a3404926 | 44 | static int frame_size; |
ad082475 | 45 | |
c5c76735 JL |
46 | /* Compute size of a clipper stack frame where 'lsize' is the required |
47 | space for local variables. */ | |
a3404926 RS |
48 | |
49 | int | |
50 | clipper_frame_size (lsize) | |
51 | int lsize; | |
ad082475 | 52 | { |
c5c76735 | 53 | int i, size; /* total size of frame */ |
ad082475 | 54 | int save_size; |
ad082475 | 55 | save_size = 0; /* compute size for reg saves */ |
a3404926 RS |
56 | |
57 | for (i = 16; i < 32; i++) | |
ad082475 RS |
58 | if (regs_ever_live[i] && !call_used_regs[i]) |
59 | save_size += 8; | |
60 | ||
61 | for (i = 0; i < 16; i++) | |
62 | if (regs_ever_live[i] && !call_used_regs[i]) | |
63 | save_size += 4; | |
64 | ||
a3404926 | 65 | size = lsize + save_size; |
ad082475 | 66 | |
ad082475 | 67 | size = (size + 7) & ~7; /* align to 64 Bit */ |
a3404926 RS |
68 | return size; |
69 | } | |
ad082475 | 70 | |
c5c76735 JL |
71 | /* Prologue and epilogue output |
72 | Function is entered with pc pushed, i.e. stack is 32 bit aligned | |
73 | ||
74 | current_function_args_size == 0 means that the current function's args | |
75 | are passed totally in registers i.e fp is not used as ap. | |
76 | If frame_size is also 0 the current function does not push anything and | |
77 | can run with misaligned stack -> subq $4,sp / add $4,sp on entry and exit | |
78 | can be omitted. */ | |
79 | ||
a3404926 RS |
80 | void |
81 | output_function_prologue (file, lsize) | |
82 | FILE *file; | |
83 | int lsize; /* size for locals */ | |
84 | { | |
85 | int i, offset; | |
86 | int size; | |
87 | ||
88 | frame_size = size = clipper_frame_size (lsize); | |
89 | ||
90 | if (frame_pointer_needed) | |
ad082475 RS |
91 | { |
92 | fputs ("\tpushw fp,sp\n", file); | |
93 | fputs ("\tmovw sp,fp\n", file); | |
94 | } | |
a3404926 RS |
95 | else if (size != 0 || current_function_args_size != 0) |
96 | { | |
97 | size += 4; /* keep stack aligned */ | |
98 | frame_size = size; /* must push data or access args */ | |
99 | } | |
100 | ||
101 | if (size) | |
ad082475 RS |
102 | { |
103 | if (size < 16) | |
a3404926 | 104 | fprintf (file, "\tsubq $%d,sp\n", size); |
ad082475 | 105 | else |
a3404926 RS |
106 | fprintf (file, "\tsubi $%d,sp\n", size); |
107 | ||
108 | /* register save slots are relative to sp, because we have small positive | |
109 | displacements and this works whether we have a frame pointer or not */ | |
110 | ||
111 | offset = 0; | |
112 | for (i = 16; i < 32; i++) | |
113 | if (regs_ever_live[i] && !call_used_regs[i]) | |
114 | { | |
115 | if (offset == 0) | |
116 | fprintf (file, "\tstord f%d,(sp)\n", i-16); | |
117 | else | |
118 | fprintf (file, "\tstord f%d,%d(sp)\n", i-16, offset); | |
119 | offset += 8; | |
120 | } | |
121 | ||
122 | for (i = 0; i < 16; i++) | |
123 | if (regs_ever_live[i] && !call_used_regs[i]) | |
124 | { | |
125 | if (offset == 0) | |
126 | fprintf (file, "\tstorw r%d,(sp)\n", i); | |
127 | else | |
128 | fprintf (file, "\tstorw r%d,%d(sp)\n", i, offset); | |
129 | offset += 4; | |
130 | } | |
ad082475 | 131 | } |
ad082475 RS |
132 | } |
133 | ||
134 | void | |
135 | output_function_epilogue (file, size) | |
136 | FILE *file; | |
137 | int size; /* ignored */ | |
138 | { | |
139 | int i, offset; | |
140 | ||
a3404926 RS |
141 | if (frame_pointer_needed) |
142 | { | |
143 | offset = -frame_size; | |
144 | ||
145 | for (i = 16; i < 32; i++) | |
146 | if (regs_ever_live[i] && !call_used_regs[i]) | |
147 | { | |
148 | fprintf (file, "\tloadd %d(fp),f%d\n", offset, i-16); | |
149 | offset += 8; | |
150 | } | |
151 | ||
152 | for (i = 0; i < 16; i++) | |
153 | if (regs_ever_live[i] && !call_used_regs[i]) | |
154 | { | |
155 | fprintf (file, "\tloadw %d(fp),r%d\n", offset, i); | |
156 | offset += 4; | |
157 | } | |
158 | ||
159 | fputs ("\tmovw fp,sp\n\tpopw sp,fp\n\tret sp\n", | |
160 | file); | |
161 | } | |
ad082475 | 162 | |
a3404926 RS |
163 | else /* no frame pointer */ |
164 | { | |
165 | offset = 0; | |
166 | ||
167 | for (i = 16; i < 32; i++) | |
168 | if (regs_ever_live[i] && !call_used_regs[i]) | |
169 | { | |
170 | if (offset == 0) | |
171 | fprintf (file, "\tloadd (sp),f%d\n", i-16); | |
172 | else | |
173 | fprintf (file, "\tloadd %d(sp),f%d\n", offset, i-16); | |
174 | offset += 8; | |
175 | } | |
176 | ||
177 | for (i = 0; i < 16; i++) | |
178 | if (regs_ever_live[i] && !call_used_regs[i]) | |
179 | { | |
180 | if (offset == 0) | |
181 | fprintf (file, "\tloadw (sp),r%d\n", i); | |
182 | else | |
183 | fprintf (file, "\tloadw %d(sp),r%d\n", offset, i); | |
184 | offset += 4; | |
185 | } | |
186 | ||
187 | if (frame_size > 0) | |
188 | { | |
189 | if (frame_size < 16) | |
190 | fprintf (file, "\taddq $%d,sp\n", frame_size); | |
191 | else | |
192 | fprintf (file, "\taddi $%d,sp\n", frame_size); | |
193 | } | |
194 | ||
195 | fputs ("\tret sp\n", file); | |
196 | } | |
ad082475 RS |
197 | } |
198 | ||
199 | /* | |
200 | * blockmove | |
201 | * | |
202 | * clipper_movstr () | |
203 | */ | |
204 | void | |
205 | clipper_movstr (operands) | |
206 | rtx *operands; | |
207 | { | |
208 | rtx dst,src,cnt,tmp,top,bottom,xops[3]; | |
209 | int align; | |
210 | int fixed; | |
211 | ||
212 | extern FILE *asm_out_file; | |
213 | ||
214 | dst = operands[0]; | |
215 | src = operands[1]; | |
216 | /* don't change this operands[2]; gcc 2.3.3 doesn't honor clobber note */ | |
217 | align = INTVAL (operands[3]); | |
218 | tmp = operands[4]; | |
219 | cnt = operands[5]; | |
220 | ||
221 | if (GET_CODE (operands[2]) == CONST_INT) /* fixed size move */ | |
222 | { | |
223 | if ((fixed = INTVAL (operands[2])) <= 0) | |
224 | abort (); | |
225 | ||
226 | if (fixed <16) | |
227 | output_asm_insn ("loadq %2,%5", operands); | |
228 | else | |
229 | output_asm_insn ("loadi %2,%5", operands); | |
230 | } | |
231 | else | |
232 | { | |
233 | fixed = 0; | |
234 | bottom = (rtx)gen_label_rtx (); /* need a bottom label */ | |
235 | xops[0] = cnt; xops[1] = bottom; | |
236 | output_asm_insn ("movw %2,%5", operands); /* count is scratch reg 5 */ | |
237 | output_asm_insn ("brle %l1", xops); | |
238 | } | |
239 | ||
240 | ||
241 | top = (rtx)gen_label_rtx (); /* top of loop label */ | |
242 | ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (top)); | |
243 | ||
244 | ||
245 | xops[0] = src; xops[1] = tmp; xops[2] = dst; | |
246 | ||
247 | if (fixed && (align & 0x3) == 0) /* word aligned move with known size */ | |
248 | { | |
249 | if (fixed >= 4) | |
250 | { | |
251 | rtx xops1[2]; | |
252 | output_asm_insn( | |
253 | "loadw %a0,%1\n\taddq $4,%0\n\tstorw %1,%a2\n\taddq $4,%2", | |
254 | xops); | |
255 | ||
256 | xops1[0] = cnt; xops1[1] = top; | |
257 | output_asm_insn ("subq $4,%0\n\tbrgt %l1", xops1); | |
258 | } | |
259 | ||
260 | if (fixed & 0x2) | |
261 | { | |
262 | output_asm_insn ("loadh %a0,%1\n\tstorh %1,%a2", xops); | |
263 | if (fixed & 0x1) | |
264 | output_asm_insn ("loadb 2%a0,%1\n\tstorb %1,2%a2", xops); | |
265 | } | |
266 | else | |
267 | if (fixed & 0x1) | |
268 | output_asm_insn ("loadb %a0,%1\n\tstorb %1,%a2", xops); | |
269 | } | |
270 | else | |
271 | { | |
272 | output_asm_insn( | |
273 | "loadb %a0,%1\n\taddq $1,%0\n\tstorb %1,%a2\n\taddq $1,%2", | |
274 | xops); | |
275 | ||
276 | xops[0] = cnt; xops[1] = top; | |
277 | output_asm_insn ("subq $1,%0\n\tbrgt %l1", xops); | |
278 | } | |
279 | ||
280 | if (fixed == 0) | |
281 | ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (bottom)); | |
282 | } | |
283 | ||
284 | \f | |
285 | print_operand_address (file, addr) | |
286 | FILE *file; | |
287 | register rtx addr; | |
288 | { | |
289 | rtx op0,op1; | |
290 | ||
291 | retry: | |
292 | switch (GET_CODE (addr)) | |
293 | { | |
294 | case REG: | |
295 | fprintf (file, "(%s)", reg_names[REGNO (addr)]); | |
296 | break; | |
297 | ||
298 | case PLUS: | |
299 | /* can be 'symbol + reg' or 'reg + reg' */ | |
300 | ||
301 | op0 = XEXP (addr, 0); | |
302 | op1 = XEXP (addr, 1); | |
303 | ||
304 | if (GET_CODE (op0) == REG && GET_CODE (op1) == REG) | |
305 | { | |
306 | fprintf (file, "[%s](%s)", | |
307 | reg_names[REGNO (op0)], reg_names[REGNO (op1)]); | |
308 | break; | |
309 | } | |
310 | ||
311 | if (GET_CODE (op0) == REG && CONSTANT_ADDRESS_P (op1)) | |
312 | { | |
313 | output_addr_const (file, op1); | |
314 | fprintf (file, "(%s)", reg_names[REGNO (op0)]); | |
315 | break; | |
316 | } | |
317 | ||
318 | if (GET_CODE (op1) == REG && CONSTANT_ADDRESS_P (op0)) | |
319 | { | |
320 | output_addr_const (file, op0); | |
321 | fprintf (file, "(%s)", reg_names[REGNO (op1)]); | |
322 | break; | |
323 | } | |
324 | abort (); /* Oh no */ | |
325 | ||
326 | default: | |
327 | output_addr_const (file, addr); | |
328 | } | |
329 | } | |
330 | ||
331 | \f | |
332 | char * | |
333 | rev_cond_name (op) | |
334 | rtx op; | |
335 | { | |
336 | switch (GET_CODE (op)) | |
337 | { | |
338 | case EQ: | |
339 | return "ne"; | |
340 | case NE: | |
341 | return "eq"; | |
342 | case LT: | |
343 | return "ge"; | |
344 | case LE: | |
345 | return "gt"; | |
346 | case GT: | |
347 | return "le"; | |
348 | case GE: | |
349 | return "lt"; | |
350 | case LTU: | |
351 | return "geu"; | |
352 | case LEU: | |
353 | return "gtu"; | |
354 | case GTU: | |
355 | return "leu"; | |
356 | case GEU: | |
357 | return "ltu"; | |
358 | ||
359 | default: | |
360 | abort (); | |
361 | } | |
362 | } | |
363 | ||
364 | \f | |
bffe09ec RH |
365 | /* Dump the argument register to the stack; return the location |
366 | of the block. */ | |
ad082475 RS |
367 | |
368 | struct rtx_def * | |
bffe09ec | 369 | clipper_builtin_saveregs () |
ad082475 | 370 | { |
bffe09ec RH |
371 | rtx block, addr, r0_addr, r1_addr, f0_addr, f1_addr, mem; |
372 | int set = get_varargs_alias_set (); | |
c21953c3 | 373 | |
bffe09ec | 374 | /* Allocate the save area for r0,r1,f0,f1 */ |
c21953c3 | 375 | |
bffe09ec | 376 | block = assign_stack_local (BLKmode, 6 * UNITS_PER_WORD, 2 * BITS_PER_WORD); |
c21953c3 | 377 | |
ad082475 RS |
378 | RTX_UNCHANGING_P (block) = 1; |
379 | RTX_UNCHANGING_P (XEXP (block, 0)) = 1; | |
380 | ||
bffe09ec | 381 | addr = XEXP (block, 0); |
ad082475 | 382 | |
bffe09ec RH |
383 | r0_addr = addr; |
384 | r1_addr = plus_constant (addr, 4); | |
385 | f0_addr = plus_constant (addr, 8); | |
386 | f1_addr = plus_constant (addr, 16); | |
ad082475 | 387 | |
bffe09ec | 388 | /* Store int regs */ |
ad082475 | 389 | |
bffe09ec RH |
390 | mem = gen_rtx_MEM (SImode, r0_addr); |
391 | MEM_ALIAS_SET (mem) = set; | |
392 | emit_move_insn (mem, gen_rtx_REG (SImode, 0)); | |
c21953c3 | 393 | |
bffe09ec RH |
394 | mem = gen_rtx_MEM (SImode, r1_addr); |
395 | MEM_ALIAS_SET (mem) = set; | |
396 | emit_move_insn (mem, gen_rtx_REG (SImode, 1)); | |
ad082475 | 397 | |
bffe09ec | 398 | /* Store float regs */ |
ad082475 | 399 | |
bffe09ec RH |
400 | mem = gen_rtx_MEM (DFmode, f0_addr); |
401 | MEM_ALIAS_SET (mem) = set; | |
402 | emit_move_insn (mem, gen_rtx_REG (DFmode, 16)); | |
ad082475 | 403 | |
bffe09ec RH |
404 | mem = gen_rtx_MEM (DFmode, f1_addr); |
405 | MEM_ALIAS_SET (mem) = set; | |
406 | emit_move_insn (mem, gen_rtx_REG (DFmode, 17)); | |
e72f998d | 407 | |
7d384cc0 | 408 | if (current_function_check_memory_usage) |
e72f998d | 409 | { |
3a598fbe JL |
410 | emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, |
411 | f0_addr, ptr_mode, | |
412 | GEN_INT (GET_MODE_SIZE (DFmode)), | |
413 | TYPE_MODE (sizetype), | |
bffe09ec | 414 | GEN_INT (MEMORY_USE_RW), |
3a598fbe JL |
415 | TYPE_MODE (integer_type_node)); |
416 | emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, | |
417 | f1_addr, ptr_mode, | |
418 | GEN_INT (GET_MODE_SIZE (DFmode)), | |
419 | TYPE_MODE (sizetype), | |
420 | GEN_INT (MEMORY_USE_RW), | |
421 | TYPE_MODE (integer_type_node)); | |
422 | emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, | |
423 | r0_addr, ptr_mode, | |
424 | GEN_INT (GET_MODE_SIZE (SImode)), | |
425 | TYPE_MODE (sizetype), | |
426 | GEN_INT (MEMORY_USE_RW), | |
427 | TYPE_MODE (integer_type_node)); | |
428 | emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, | |
429 | r1_addr, ptr_mode, | |
430 | GEN_INT (GET_MODE_SIZE (SImode)), | |
e72f998d | 431 | TYPE_MODE (sizetype), |
3a598fbe JL |
432 | GEN_INT (MEMORY_USE_RW), |
433 | TYPE_MODE (integer_type_node)); | |
e72f998d RK |
434 | } |
435 | ||
bffe09ec RH |
436 | return addr; |
437 | } | |
438 | ||
439 | tree | |
440 | clipper_build_va_list () | |
441 | { | |
442 | tree record, ap, reg, num; | |
443 | ||
444 | /* | |
445 | struct | |
446 | { | |
447 | int __va_ap; // pointer to stack args | |
448 | void *__va_reg[4]; // pointer to r0,f0,r1,f1 | |
449 | int __va_num; // number of args processed | |
450 | }; | |
451 | */ | |
452 | ||
453 | record = make_node (RECORD_TYPE); | |
454 | ||
455 | num = build_decl (FIELD_DECL, get_identifier ("__va_num"), | |
456 | integer_type_node); | |
457 | DECL_FIELD_CONTEXT (num) = record; | |
458 | ||
459 | reg = build_decl (FIELD_DECL, get_identifier ("__va_reg"), | |
460 | build_array_type (ptr_type_node, | |
461 | build_index_type (build_int_2 (3, 0)))); | |
462 | DECL_FIELD_CONTEXT (reg) = record; | |
463 | TREE_CHAIN (reg) = num; | |
464 | ||
465 | ap = build_decl (FIELD_DECL, get_identifier ("__va_ap"), | |
466 | integer_type_node); | |
467 | DECL_FIELD_CONTEXT (ap) = record; | |
468 | TREE_CHAIN (ap) = reg; | |
469 | ||
470 | TYPE_FIELDS (record) = ap; | |
471 | layout_type (record); | |
472 | ||
473 | return record; | |
474 | } | |
475 | ||
476 | void | |
477 | clipper_va_start (stdarg_p, valist, nextarg) | |
478 | int stdarg_p; | |
479 | tree valist; | |
480 | rtx nextarg ATTRIBUTE_UNUSED; | |
481 | { | |
482 | tree ap_field, reg_field, num_field; | |
483 | tree t, u, save_area; | |
484 | ||
485 | ap_field = TYPE_FIELDS (TREE_TYPE (valist)); | |
486 | reg_field = TREE_CHAIN (ap_field); | |
487 | num_field = TREE_CHAIN (reg_field); | |
488 | ||
489 | ap_field = build (COMPONENT_REF, TREE_TYPE (ap_field), valist, ap_field); | |
490 | reg_field = build (COMPONENT_REF, TREE_TYPE (reg_field), valist, reg_field); | |
491 | num_field = build (COMPONENT_REF, TREE_TYPE (num_field), valist, num_field); | |
492 | ||
493 | /* Call __builtin_saveregs to save r0, r1, f0, and f1 in a block. */ | |
494 | ||
495 | save_area = make_tree (integer_type_node, expand_builtin_saveregs ()); | |
496 | ||
497 | /* Set __va_ap. */ | |
498 | ||
499 | t = make_tree (ptr_type_node, virtual_incoming_args_rtx); | |
500 | if (stdarg_p && current_function_args_info.size != 0) | |
501 | t = build (PLUS_EXPR, ptr_type_node, t, | |
502 | build_int_2 (current_function_args_info.size, 0)); | |
503 | t = build (MODIFY_EXPR, TREE_TYPE (ap_field), ap_field, t); | |
7a3842b3 | 504 | TREE_SIDE_EFFECTS (t) = 1; |
bffe09ec RH |
505 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); |
506 | ||
507 | /* Set the four entries of __va_reg. */ | |
508 | ||
509 | t = build1 (NOP_EXPR, ptr_type_node, save_area); | |
510 | u = build (ARRAY_REF, ptr_type_node, reg_field, build_int (0, 0)); | |
511 | t = build (MODIFY_EXPR, ptr_type_node, u, t); | |
7a3842b3 | 512 | TREE_SIDE_EFFECTS (t) = 1; |
bffe09ec RH |
513 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); |
514 | ||
515 | t = fold (build (PLUS_EXPR, integer_type_node, save_area, | |
516 | build_int_2 (8, 0))); | |
517 | t = build1 (NOP_EXPR, ptr_type_node, save_area); | |
518 | u = build (ARRAY_REF, ptr_type_node, reg_field, build_int (1, 0)); | |
519 | t = build (MODIFY_EXPR, ptr_type_node, u, t); | |
7a3842b3 | 520 | TREE_SIDE_EFFECTS (t) = 1; |
bffe09ec RH |
521 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); |
522 | ||
523 | t = fold (build (PLUS_EXPR, integer_type_node, save_area, | |
524 | build_int_2 (4, 0))); | |
525 | t = build1 (NOP_EXPR, ptr_type_node, save_area); | |
526 | u = build (ARRAY_REF, ptr_type_node, reg_field, build_int (2, 0)); | |
527 | t = build (MODIFY_EXPR, ptr_type_node, u, t); | |
7a3842b3 | 528 | TREE_SIDE_EFFECTS (t) = 1; |
bffe09ec RH |
529 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); |
530 | ||
531 | t = fold (build (PLUS_EXPR, integer_type_node, save_area, | |
532 | build_int_2 (16, 0))); | |
533 | t = build1 (NOP_EXPR, ptr_type_node, save_area); | |
534 | u = build (ARRAY_REF, ptr_type_node, reg_field, build_int (3, 0)); | |
535 | t = build (MODIFY_EXPR, ptr_type_node, u, t); | |
7a3842b3 | 536 | TREE_SIDE_EFFECTS (t) = 1; |
bffe09ec RH |
537 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); |
538 | ||
539 | /* Set __va_num. */ | |
540 | ||
541 | t = build_int_2 (current_function_args_info.num, 0); | |
542 | t = build (MODIFY_EXPR, TREE_TYPE (num_field), num_field, t); | |
7a3842b3 RH |
543 | TREE_SIDE_EFFECTS (t) = 1; |
544 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
ad082475 RS |
545 | } |
546 | ||
bffe09ec RH |
547 | rtx |
548 | clipper_va_arg (valist, type) | |
549 | tree valist, type; | |
550 | { | |
551 | tree ap_field, reg_field, num_field; | |
552 | tree addr, t; | |
553 | HOST_WIDE_INT align; | |
554 | rtx addr_rtx, over_label = NULL_RTX, tr; | |
555 | ||
556 | /* | |
557 | Integers: | |
558 | ||
559 | if (VA.__va_num < 2) | |
560 | addr = VA.__va_reg[2 * VA.__va_num]; | |
561 | else | |
562 | addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE); | |
563 | VA.__va_num++; | |
564 | ||
565 | Floats: | |
566 | ||
567 | if (VA.__va_num < 2) | |
568 | addr = VA.__va_reg[2 * VA.__va_num + 1]; | |
569 | else | |
570 | addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE); | |
571 | VA.__va_num++; | |
572 | ||
573 | Aggregates: | |
574 | ||
575 | addr = round(VA.__va_ap), VA.__va_ap = round(VA.__va_ap) + sizeof(TYPE); | |
576 | VA.__va_num++; | |
577 | */ | |
578 | ||
579 | ap_field = TYPE_FIELDS (TREE_TYPE (valist)); | |
580 | reg_field = TREE_CHAIN (ap_field); | |
581 | num_field = TREE_CHAIN (reg_field); | |
582 | ||
583 | ap_field = build (COMPONENT_REF, TREE_TYPE (ap_field), valist, ap_field); | |
584 | reg_field = build (COMPONENT_REF, TREE_TYPE (reg_field), valist, reg_field); | |
585 | num_field = build (COMPONENT_REF, TREE_TYPE (num_field), valist, num_field); | |
586 | ||
587 | addr_rtx = gen_reg_rtx (Pmode); | |
588 | ||
589 | if (! AGGREGATE_TYPE_P (type)) | |
590 | { | |
591 | tree inreg; | |
592 | rtx false_label; | |
593 | ||
594 | over_label = gen_label_rtx (); | |
595 | false_label = gen_label_rtx (); | |
596 | ||
597 | emit_cmp_and_jump_insns (expand_expr (num_field, NULL_RTX, 0, | |
598 | OPTAB_LIB_WIDEN), | |
599 | GEN_INT (2), GE, const0_rtx, | |
600 | TYPE_MODE (TREE_TYPE (num_field)), | |
601 | TREE_UNSIGNED (num_field), 0, false_label); | |
602 | ||
603 | inreg = fold (build (MULT_EXPR, integer_type_node, num_field, | |
604 | build_int_2 (2, 0))); | |
605 | if (FLOAT_TYPE_P (type)) | |
606 | inreg = fold (build (PLUS_EXPR, integer_type_node, inreg, | |
607 | build_int_2 (1, 0))); | |
608 | inreg = fold (build (ARRAY_REF, ptr_type_node, reg_field, inreg)); | |
609 | ||
610 | tr = expand_expr (inreg, addr_rtx, VOIDmode, EXPAND_NORMAL); | |
611 | if (tr != addr_rtx) | |
612 | emit_move_insn (addr_rtx, tr); | |
613 | ||
614 | emit_jump_insn (gen_jump (over_label)); | |
615 | emit_barrier (); | |
616 | emit_label (false_label); | |
617 | } | |
618 | ||
619 | /* Round to alignment of `type', or at least integer alignment. */ | |
620 | ||
621 | align = TYPE_ALIGN (type); | |
622 | if (align < TYPE_ALIGN (integer_type_node)) | |
623 | align = TYPE_ALIGN (integer_type_node); | |
624 | align /= BITS_PER_UNIT; | |
625 | ||
626 | addr = fold (build (PLUS_EXPR, ptr_type_node, ap_field, | |
627 | build_int_2 (align-1, 0))); | |
628 | addr = fold (build (BIT_AND_EXPR, ptr_type_node, addr, | |
629 | build_int_2 (-align, -1))); | |
630 | addr = save_expr (addr); | |
631 | ||
632 | tr = expand_expr (addr, addr_rtx, Pmode, EXPAND_NORMAL); | |
633 | if (tr != addr_rtx) | |
634 | emit_move_insn (addr_rtx, tr); | |
635 | ||
636 | t = build (MODIFY_EXPR, TREE_TYPE (ap_field), ap_field, | |
637 | build (PLUS_EXPR, TREE_TYPE (ap_field), | |
638 | addr, build_int_2 (int_size_in_bytes (type), 0))); | |
639 | TREE_SIDE_EFFECTS (t) = 1; | |
640 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
641 | ||
642 | if (over_label) | |
643 | emit_label (over_label); | |
644 | ||
645 | t = build (MODIFY_EXPR, TREE_TYPE (num_field), num_field, | |
646 | build (PLUS_EXPR, TREE_TYPE (num_field), | |
647 | num_field, build_int_2 (1, 0))); | |
648 | TREE_SIDE_EFFECTS (t) = 1; | |
649 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
650 | ||
651 | return addr_rtx; | |
652 | } | |
ad082475 RS |
653 | |
654 | /* Return truth value of whether OP can be used as an word register | |
655 | operand. Reject (SUBREG:SI (REG:SF )) */ | |
656 | ||
657 | int | |
658 | int_reg_operand (op, mode) | |
659 | rtx op; | |
660 | enum machine_mode mode; | |
661 | { | |
662 | return (register_operand (op, mode) && | |
663 | (GET_CODE (op) != SUBREG || | |
664 | GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_INT)); | |
665 | } | |
666 | ||
667 | /* Return truth value of whether OP can be used as a float register | |
668 | operand. Reject (SUBREG:SF (REG:SI )) )) */ | |
669 | ||
670 | int | |
671 | fp_reg_operand (op, mode) | |
672 | rtx op; | |
673 | enum machine_mode mode; | |
674 | { | |
675 | return (register_operand (op, mode) && | |
676 | (GET_CODE (op) != SUBREG || | |
677 | GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_FLOAT)); | |
678 | } | |
679 |