]>
Commit | Line | Data |
---|---|---|
11bb1f11 JL |
1 | /* Subroutines for insn-output.c for Matsushita MN10300 series |
2 | Copyright (C) 1996 Free Software Foundation, Inc. | |
3 | Contributed by Jeff Law (law@cygnus.com). | |
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 | |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, | |
20 | Boston, MA 02111-1307, 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 "flags.h" | |
34 | #include "recog.h" | |
35 | #include "expr.h" | |
36 | #include "tree.h" | |
37 | #include "obstack.h" | |
38 | ||
39 | void | |
40 | asm_file_start (file) | |
41 | FILE *file; | |
42 | { | |
43 | fprintf (file, "#\tGCC For the Matsushita MN10300\n"); | |
44 | if (optimize) | |
45 | fprintf (file, "# -O%d\n", optimize); | |
46 | else | |
47 | fprintf (file, "\n\n"); | |
48 | output_file_directive (file, main_input_filename); | |
49 | } | |
50 | \f | |
51 | ||
52 | int | |
53 | const_costs (r, c) | |
54 | rtx r; | |
55 | enum rtx_code c; | |
56 | { | |
57 | switch (c) | |
58 | { | |
59 | case CONST_INT: | |
60 | if (INT_8_BITS (INTVAL (r))) | |
61 | return 0; | |
62 | else if (INT_16_BITS (INTVAL (r))) | |
63 | return 1; | |
64 | else | |
65 | return 2; | |
66 | case CONST_DOUBLE: | |
67 | return 8; | |
68 | default: | |
69 | return 4; | |
70 | } | |
71 | } | |
72 | \f | |
73 | /* Print operand X using operand code CODE to assembly language output file | |
74 | FILE. */ | |
75 | ||
76 | void | |
77 | print_operand (file, x, code) | |
78 | FILE *file; | |
79 | rtx x; | |
80 | int code; | |
81 | { | |
82 | switch (code) | |
83 | { | |
84 | case 'b': | |
85 | case 'B': | |
86 | /* These are normal and reversed branches. */ | |
87 | switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x))) | |
88 | { | |
89 | case NE: | |
90 | fprintf (file, "ne"); | |
91 | break; | |
92 | case EQ: | |
93 | fprintf (file, "eq"); | |
94 | break; | |
95 | case GE: | |
96 | fprintf (file, "ge"); | |
97 | break; | |
98 | case GT: | |
99 | fprintf (file, "gt"); | |
100 | break; | |
101 | case LE: | |
102 | fprintf (file, "le"); | |
103 | break; | |
104 | case LT: | |
105 | fprintf (file, "lt"); | |
106 | break; | |
107 | case GEU: | |
108 | fprintf (file, "cc"); | |
109 | break; | |
110 | case GTU: | |
111 | fprintf (file, "hi"); | |
112 | break; | |
113 | case LEU: | |
114 | fprintf (file, "ls"); | |
115 | break; | |
116 | case LTU: | |
117 | fprintf (file, "cs"); | |
118 | break; | |
119 | default: | |
120 | abort (); | |
121 | } | |
122 | break; | |
123 | case 'C': | |
124 | /* This is used for the operand to a call instruction; | |
125 | if it's a REG, enclose it in parens, else output | |
126 | the operand normally. */ | |
127 | if (GET_CODE (x) == REG) | |
128 | { | |
129 | fputc ('(', file); | |
130 | print_operand (file, x, 0); | |
131 | fputc (')', file); | |
132 | } | |
133 | else | |
134 | print_operand (file, x, 0); | |
135 | break; | |
136 | ||
137 | default: | |
138 | switch (GET_CODE (x)) | |
139 | { | |
140 | case MEM: | |
141 | fputc ('(', file); | |
142 | output_address (XEXP (x, 0)); | |
143 | fputc (')', file); | |
144 | break; | |
145 | ||
146 | case REG: | |
147 | fprintf (file, "%s", reg_names[REGNO (x)]); | |
148 | break; | |
149 | ||
150 | case SUBREG: | |
151 | fprintf (file, "%s", | |
152 | reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]); | |
153 | break; | |
154 | ||
155 | case CONST_INT: | |
156 | case SYMBOL_REF: | |
157 | case CONST: | |
158 | case LABEL_REF: | |
159 | case CODE_LABEL: | |
160 | print_operand_address (file, x); | |
161 | break; | |
162 | default: | |
163 | abort (); | |
164 | } | |
165 | break; | |
166 | } | |
167 | } | |
168 | ||
169 | /* Output assembly language output for the address ADDR to FILE. */ | |
170 | ||
171 | void | |
172 | print_operand_address (file, addr) | |
173 | FILE *file; | |
174 | rtx addr; | |
175 | { | |
176 | switch (GET_CODE (addr)) | |
177 | { | |
178 | case REG: | |
179 | if (addr == stack_pointer_rtx) | |
180 | print_operand_address (file, gen_rtx (PLUS, SImode, | |
181 | stack_pointer_rtx, | |
182 | GEN_INT (0))); | |
183 | else | |
184 | print_operand (file, addr, 0); | |
185 | break; | |
186 | case PLUS: | |
187 | { | |
188 | rtx base, index; | |
189 | if (REG_P (XEXP (addr, 0)) | |
190 | && REG_OK_FOR_BASE_P (XEXP (addr, 0))) | |
191 | base = XEXP (addr, 0), index = XEXP (addr, 1); | |
192 | else if (REG_P (XEXP (addr, 1)) | |
193 | && REG_OK_FOR_BASE_P (XEXP (addr, 1))) | |
194 | base = XEXP (addr, 1), index = XEXP (addr, 0); | |
195 | else | |
196 | abort (); | |
197 | print_operand (file, index, 0); | |
198 | fputc (',', file); | |
199 | print_operand (file, base, 0);; | |
200 | break; | |
201 | } | |
202 | case SYMBOL_REF: | |
203 | output_addr_const (file, addr); | |
204 | break; | |
205 | default: | |
206 | output_addr_const (file, addr); | |
207 | break; | |
208 | } | |
209 | } | |
210 | ||
211 | void | |
212 | expand_prologue () | |
213 | { | |
214 | unsigned int size = get_frame_size (); | |
215 | ||
216 | /* For simplicity, we just movm all the callee saved registers to | |
217 | the stack with one instruction, then set up the frame pointer | |
218 | (if needed), and finally allocate the new stack. */ | |
219 | emit_insn (gen_store_movm ()); | |
220 | ||
221 | if (frame_pointer_needed) | |
222 | { | |
223 | emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); | |
224 | emit_insn (gen_addsi3 (frame_pointer_rtx, | |
225 | frame_pointer_rtx, | |
226 | GEN_INT (20))); | |
227 | } | |
228 | ||
229 | if (size) | |
230 | emit_insn (gen_addsi3 (stack_pointer_rtx, | |
231 | stack_pointer_rtx, | |
232 | GEN_INT (-size))); | |
233 | } | |
234 | ||
235 | void | |
236 | expand_epilogue () | |
237 | { | |
238 | unsigned int size = get_frame_size (); | |
239 | ||
240 | /* Cut back the stack. */ | |
241 | if (frame_pointer_needed) | |
242 | { | |
243 | emit_insn (gen_addsi3 (frame_pointer_rtx, | |
244 | frame_pointer_rtx, | |
245 | GEN_INT (-20))); | |
246 | emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); | |
247 | } | |
248 | else if (size) | |
249 | emit_insn (gen_addsi3 (stack_pointer_rtx, | |
250 | stack_pointer_rtx, | |
251 | GEN_INT (size))); | |
252 | ||
253 | /* And restore the registers. */ | |
254 | emit_insn (gen_load_movm ()); | |
255 | ||
256 | /* And return. */ | |
257 | emit_jump_insn (gen_return_internal ()); | |
258 | } | |
259 | ||
260 | /* Update the condition code from the insn. */ | |
261 | ||
262 | void | |
263 | notice_update_cc (body, insn) | |
264 | rtx body; | |
265 | rtx insn; | |
266 | { | |
267 | #if 0 | |
268 | switch (get_attr_cc (insn)) | |
269 | { | |
270 | case CC_NONE: | |
271 | /* Insn does not affect CC at all. */ | |
272 | break; | |
273 | ||
274 | case CC_NONE_0HIT: | |
275 | /* Insn does not change CC, but the 0'th operand has been changed. */ | |
276 | if (cc_status.value1 != 0 | |
277 | && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1)) | |
278 | cc_status.value1 = 0; | |
279 | break; | |
280 | ||
281 | case CC_SET_ZN_C0: | |
282 | /* Insn sets the Z,N flags of CC to recog_operand[0]. | |
283 | V is always set to 0. C may or may not be set to 0 but that's ok | |
284 | because alter_cond will change tests to use EQ/NE. */ | |
285 | CC_STATUS_INIT; | |
286 | cc_status.flags |= CC_NO_OVERFLOW; | |
287 | cc_status.value1 = recog_operand[0]; | |
288 | break; | |
289 | ||
290 | case CC_SET: | |
291 | case CC_COMPARE: | |
292 | /* The insn is a compare instruction. */ | |
293 | CC_STATUS_INIT; | |
294 | cc_status.value1 = SET_SRC (body); | |
295 | break; | |
296 | ||
297 | case CC_CLOBBER: | |
298 | /* Insn doesn't leave CC in a usable state. */ | |
299 | CC_STATUS_INIT; | |
300 | break; | |
301 | } | |
302 | #endif | |
303 | CC_STATUS_INIT; | |
304 | } | |
305 | ||
306 | /* Return true if OP is a valid call operand. */ | |
307 | ||
308 | int | |
309 | call_address_operand (op, mode) | |
310 | rtx op; | |
311 | enum machine_mode mode; | |
312 | { | |
313 | return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG); | |
314 | } | |
315 | ||
316 | /* What (if any) secondary registers are needed to move IN with mode | |
317 | MODE into a register from in register class CLASS. | |
318 | ||
319 | We might be able to simplify this. */ | |
320 | enum reg_class | |
321 | secondary_reload_class (class, mode, in) | |
322 | enum reg_class class; | |
323 | enum machine_mode mode; | |
324 | rtx in; | |
325 | { | |
326 | int regno; | |
327 | ||
328 | /* Memory loads less than a full word wide can't have an | |
329 | address or stack pointer destination. They must use | |
330 | a data register as an intermediate register. */ | |
331 | if (GET_CODE (in) == MEM | |
332 | && (mode == QImode || mode == HImode) | |
333 | && (class == ADDRESS_REGS || class == SP_REGS)) | |
334 | return DATA_REGS; | |
335 | ||
336 | /* We can't directly load sp + const_int into a data register; | |
337 | we must use an address register as an intermediate. */ | |
338 | if (class == DATA_REGS | |
339 | && (in == stack_pointer_rtx | |
340 | || (GET_CODE (in) == PLUS | |
341 | && XEXP (in, 0) == stack_pointer_rtx))) | |
342 | return ADDRESS_REGS; | |
343 | ||
344 | /* Get the true register. */ | |
345 | if (GET_CODE (in) == REG) | |
346 | { | |
347 | regno = REGNO (in); | |
348 | if (regno >= FIRST_PSEUDO_REGISTER) | |
349 | regno = true_regnum (in); | |
350 | } | |
351 | ||
352 | /* We can't copy directly from a data register into the stack | |
353 | pointer. */ | |
354 | if (class == SP_REGS | |
355 | && GET_CODE (in) == REG | |
356 | && regno < 4) | |
357 | return ADDRESS_REGS; | |
358 | ||
359 | /* Otherwise assume no secondary reloads are needed. */ | |
360 | return NO_REGS; | |
361 | } |