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