|
|
1.1 root 1: /* Subroutines for insn-output.c for Clipper
2: Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc.
3:
4: Contributed by Holger Teutsch ([email protected])
5:
6: This file is part of GNU CC.
7:
8: GNU CC 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 2, or (at your option)
11: any later version.
12:
13: GNU CC 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 GNU CC; see the file COPYING. If not, write to
20: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21:
22: #include <stdio.h>
23: #include "config.h"
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"
35: #include "expr.h"
36: #include "flags.h"
37: #include "machmode.h"
38:
39: extern char regs_ever_live[];
40:
41: extern int frame_pointer_needed;
42:
43: static int frame_size;
44:
45: /*
46: * compute size of a clipper stack frame where 'lsize' is the required
47: * space for local variables.
48: */
49:
50: int
51: clipper_frame_size (lsize)
52: int lsize;
53: {
54: int i,size; /* total size of frame */
55: int save_size;
56: save_size = 0; /* compute size for reg saves */
57:
58: for (i = 16; i < 32; i++)
59: if (regs_ever_live[i] && !call_used_regs[i])
60: save_size += 8;
61:
62: for (i = 0; i < 16; i++)
63: if (regs_ever_live[i] && !call_used_regs[i])
64: save_size += 4;
65:
66: size = lsize + save_size;
67:
68: size = (size + 7) & ~7; /* align to 64 Bit */
69: return size;
70: }
71:
72: /*
73: * prologue and epilogue output
74: * function is entered with pc pushed, i.e. stack is 32 bit aligned
75: *
76: * current_function_args_size == 0 means that the current function's args
77: * are passed totally in registers i.e fp is not used as ap.
78: * If frame_size is also 0 the current function does not push anything and
79: * can run with misaligned stack -> subq $4,sp / add $4,sp on entry and exit
80: * can be omitted.
81: *
82: */
83: void
84: output_function_prologue (file, lsize)
85: FILE *file;
86: int lsize; /* size for locals */
87: {
88: int i, offset;
89: int size;
90:
91: frame_size = size = clipper_frame_size (lsize);
92:
93: if (frame_pointer_needed)
94: {
95: fputs ("\tpushw fp,sp\n", file);
96: fputs ("\tmovw sp,fp\n", file);
97: }
98: else if (size != 0 || current_function_args_size != 0)
99: {
100: size += 4; /* keep stack aligned */
101: frame_size = size; /* must push data or access args */
102: }
103:
104: if (size)
105: {
106: if (size < 16)
107: fprintf (file, "\tsubq $%d,sp\n", size);
108: else
109: fprintf (file, "\tsubi $%d,sp\n", size);
110:
111: /* register save slots are relative to sp, because we have small positive
112: displacements and this works whether we have a frame pointer or not */
113:
114: offset = 0;
115: for (i = 16; i < 32; i++)
116: if (regs_ever_live[i] && !call_used_regs[i])
117: {
118: if (offset == 0)
119: fprintf (file, "\tstord f%d,(sp)\n", i-16);
120: else
121: fprintf (file, "\tstord f%d,%d(sp)\n", i-16, offset);
122: offset += 8;
123: }
124:
125: for (i = 0; i < 16; i++)
126: if (regs_ever_live[i] && !call_used_regs[i])
127: {
128: if (offset == 0)
129: fprintf (file, "\tstorw r%d,(sp)\n", i);
130: else
131: fprintf (file, "\tstorw r%d,%d(sp)\n", i, offset);
132: offset += 4;
133: }
134: }
135: }
136:
137: void
138: output_function_epilogue (file, size)
139: FILE *file;
140: int size; /* ignored */
141: {
142: int i, offset;
143:
144: if (frame_pointer_needed)
145: {
146: offset = -frame_size;
147:
148: for (i = 16; i < 32; i++)
149: if (regs_ever_live[i] && !call_used_regs[i])
150: {
151: fprintf (file, "\tloadd %d(fp),f%d\n", offset, i-16);
152: offset += 8;
153: }
154:
155: for (i = 0; i < 16; i++)
156: if (regs_ever_live[i] && !call_used_regs[i])
157: {
158: fprintf (file, "\tloadw %d(fp),r%d\n", offset, i);
159: offset += 4;
160: }
161:
162: fputs ("\tmovw fp,sp\n\tpopw sp,fp\n\tret sp\n",
163: file);
164: }
165:
166: else /* no frame pointer */
167: {
168: offset = 0;
169:
170: for (i = 16; i < 32; i++)
171: if (regs_ever_live[i] && !call_used_regs[i])
172: {
173: if (offset == 0)
174: fprintf (file, "\tloadd (sp),f%d\n", i-16);
175: else
176: fprintf (file, "\tloadd %d(sp),f%d\n", offset, i-16);
177: offset += 8;
178: }
179:
180: for (i = 0; i < 16; i++)
181: if (regs_ever_live[i] && !call_used_regs[i])
182: {
183: if (offset == 0)
184: fprintf (file, "\tloadw (sp),r%d\n", i);
185: else
186: fprintf (file, "\tloadw %d(sp),r%d\n", offset, i);
187: offset += 4;
188: }
189:
190: if (frame_size > 0)
191: {
192: if (frame_size < 16)
193: fprintf (file, "\taddq $%d,sp\n", frame_size);
194: else
195: fprintf (file, "\taddi $%d,sp\n", frame_size);
196: }
197:
198: fputs ("\tret sp\n", file);
199: }
200: }
201:
202: /*
203: * blockmove
204: *
205: * clipper_movstr ()
206: */
207: void
208: clipper_movstr (operands)
209: rtx *operands;
210: {
211: rtx dst,src,cnt,tmp,top,bottom,xops[3];
212: int align;
213: int fixed;
214:
215: extern FILE *asm_out_file;
216:
217: dst = operands[0];
218: src = operands[1];
219: /* don't change this operands[2]; gcc 2.3.3 doesn't honor clobber note */
220: align = INTVAL (operands[3]);
221: tmp = operands[4];
222: cnt = operands[5];
223:
224: if (GET_CODE (operands[2]) == CONST_INT) /* fixed size move */
225: {
226: if ((fixed = INTVAL (operands[2])) <= 0)
227: abort ();
228:
229: if (fixed <16)
230: output_asm_insn ("loadq %2,%5", operands);
231: else
232: output_asm_insn ("loadi %2,%5", operands);
233: }
234: else
235: {
236: fixed = 0;
237: bottom = (rtx)gen_label_rtx (); /* need a bottom label */
238: xops[0] = cnt; xops[1] = bottom;
239: output_asm_insn ("movw %2,%5", operands); /* count is scratch reg 5 */
240: output_asm_insn ("brle %l1", xops);
241: }
242:
243:
244: top = (rtx)gen_label_rtx (); /* top of loop label */
245: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (top));
246:
247:
248: xops[0] = src; xops[1] = tmp; xops[2] = dst;
249:
250: if (fixed && (align & 0x3) == 0) /* word aligned move with known size */
251: {
252: if (fixed >= 4)
253: {
254: rtx xops1[2];
255: output_asm_insn(
256: "loadw %a0,%1\n\taddq $4,%0\n\tstorw %1,%a2\n\taddq $4,%2",
257: xops);
258:
259: xops1[0] = cnt; xops1[1] = top;
260: output_asm_insn ("subq $4,%0\n\tbrgt %l1", xops1);
261: }
262:
263: if (fixed & 0x2)
264: {
265: output_asm_insn ("loadh %a0,%1\n\tstorh %1,%a2", xops);
266: if (fixed & 0x1)
267: output_asm_insn ("loadb 2%a0,%1\n\tstorb %1,2%a2", xops);
268: }
269: else
270: if (fixed & 0x1)
271: output_asm_insn ("loadb %a0,%1\n\tstorb %1,%a2", xops);
272: }
273: else
274: {
275: output_asm_insn(
276: "loadb %a0,%1\n\taddq $1,%0\n\tstorb %1,%a2\n\taddq $1,%2",
277: xops);
278:
279: xops[0] = cnt; xops[1] = top;
280: output_asm_insn ("subq $1,%0\n\tbrgt %l1", xops);
281: }
282:
283: if (fixed == 0)
284: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (bottom));
285: }
286:
287:
288: print_operand_address (file, addr)
289: FILE *file;
290: register rtx addr;
291: {
292: rtx op0,op1;
293:
294: retry:
295: switch (GET_CODE (addr))
296: {
297: case REG:
298: fprintf (file, "(%s)", reg_names[REGNO (addr)]);
299: break;
300:
301: case PLUS:
302: /* can be 'symbol + reg' or 'reg + reg' */
303:
304: op0 = XEXP (addr, 0);
305: op1 = XEXP (addr, 1);
306:
307: if (GET_CODE (op0) == REG && GET_CODE (op1) == REG)
308: {
309: fprintf (file, "[%s](%s)",
310: reg_names[REGNO (op0)], reg_names[REGNO (op1)]);
311: break;
312: }
313:
314: if (GET_CODE (op0) == REG && CONSTANT_ADDRESS_P (op1))
315: {
316: output_addr_const (file, op1);
317: fprintf (file, "(%s)", reg_names[REGNO (op0)]);
318: break;
319: }
320:
321: if (GET_CODE (op1) == REG && CONSTANT_ADDRESS_P (op0))
322: {
323: output_addr_const (file, op0);
324: fprintf (file, "(%s)", reg_names[REGNO (op1)]);
325: break;
326: }
327: abort (); /* Oh no */
328:
329: default:
330: output_addr_const (file, addr);
331: }
332: }
333:
334:
335: char *
336: rev_cond_name (op)
337: rtx op;
338: {
339: switch (GET_CODE (op))
340: {
341: case EQ:
342: return "ne";
343: case NE:
344: return "eq";
345: case LT:
346: return "ge";
347: case LE:
348: return "gt";
349: case GT:
350: return "le";
351: case GE:
352: return "lt";
353: case LTU:
354: return "geu";
355: case LEU:
356: return "gtu";
357: case GTU:
358: return "leu";
359: case GEU:
360: return "ltu";
361:
362: default:
363: abort ();
364: }
365: }
366:
367:
368: /* Do what is necessary for `va_start'. The argument is ignored;
369: We fill in an initial va_list. A pointer to this constructor
370: is returned. */
371:
372:
373: struct rtx_def *
374: clipper_builtin_saveregs (arglist)
375: tree arglist;
376: {
377: extern int current_function_varargs;
378: rtx block, addr, argsize, scratch, r0_addr,r1_addr,f0_addr,f1_addr;
379:
380: /* Allocate the va_list constructor + save area for r0,r1,f0,f1 */
381:
382: block = assign_stack_local (BLKmode,
383: (6 + 6) * UNITS_PER_WORD, 2 * BITS_PER_WORD);
384:
385: RTX_UNCHANGING_P (block) = 1;
386: RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
387:
388: addr = copy_to_reg (XEXP (block, 0));
389:
390: f0_addr = gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 24));
391: f1_addr = gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 32));
392: r0_addr = gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 40));
393: r1_addr = gen_rtx (PLUS, Pmode, addr, gen_rtx (CONST_INT, Pmode, 44));
394:
395:
396: /* Store float regs */
397:
398: emit_move_insn (gen_rtx (MEM, DFmode, f0_addr), gen_rtx (REG, DFmode, 16));
399: emit_move_insn (gen_rtx (MEM, DFmode, f1_addr), gen_rtx (REG, DFmode, 17));
400:
401: /* Store int regs */
402:
403: emit_move_insn (gen_rtx (MEM, SImode, r0_addr), gen_rtx (REG, SImode, 0));
404: emit_move_insn (gen_rtx (MEM, SImode, r1_addr), gen_rtx (REG, SImode, 1));
405:
406: /* Store the arg pointer in the __va_stk member. */
407:
408: emit_move_insn (gen_rtx (MEM, SImode, addr),
409: copy_to_reg (virtual_incoming_args_rtx));
410:
411:
412: /* now move addresses of the saved regs into the pointer array */
413:
414: scratch = gen_reg_rtx (Pmode);
415:
416: emit_move_insn (scratch, r0_addr);
417: emit_move_insn (gen_rtx (MEM, SImode,
418: gen_rtx (PLUS, Pmode, addr,
419: gen_rtx (CONST_INT, Pmode, 4))),
420: scratch);
421:
422: emit_move_insn (scratch, f0_addr);
423: emit_move_insn (gen_rtx (MEM, SImode,
424: gen_rtx (PLUS, Pmode, addr,
425: gen_rtx (CONST_INT, Pmode, 8))),
426: scratch);
427:
428: emit_move_insn (scratch, r1_addr);
429: emit_move_insn (gen_rtx (MEM, SImode,
430: gen_rtx (PLUS, Pmode, addr,
431: gen_rtx (CONST_INT, Pmode, 12))),
432: scratch);
433:
434: emit_move_insn (scratch, f1_addr);
435: emit_move_insn (gen_rtx (MEM, SImode,
436: gen_rtx (PLUS, Pmode, addr,
437: gen_rtx (CONST_INT, Pmode, 16))),
438: scratch);
439:
440: /* Return the address of the va_list constructor, but don't put it in a
441: register. This fails when not optimizing and produces worse code when
442: optimizing. */
443:
444: return XEXP (block, 0);
445: }
446:
447:
448: /* Return truth value of whether OP can be used as an word register
449: operand. Reject (SUBREG:SI (REG:SF )) */
450:
451: int
452: int_reg_operand (op, mode)
453: rtx op;
454: enum machine_mode mode;
455: {
456: return (register_operand (op, mode) &&
457: (GET_CODE (op) != SUBREG ||
458: GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_INT));
459: }
460:
461: /* Return truth value of whether OP can be used as a float register
462: operand. Reject (SUBREG:SF (REG:SI )) )) */
463:
464: int
465: fp_reg_operand (op, mode)
466: rtx op;
467: enum machine_mode mode;
468: {
469: return (register_operand (op, mode) &&
470: (GET_CODE (op) != SUBREG ||
471: GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) == MODE_FLOAT));
472: }
473:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.