]>
Commit | Line | Data |
---|---|---|
16bea517 | 1 | /* Output routines for GCC for Hitachi Super-H. |
8aa2a305 | 2 | Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. |
bc45ade3 | 3 | |
0d7e008e | 4 | This file is part of GNU CC. |
bc45ade3 | 5 | |
0d7e008e SC |
6 | GNU CC is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2, or (at your option) | |
9 | any later version. | |
bc45ade3 | 10 | |
0d7e008e SC |
11 | GNU CC is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
bc45ade3 | 15 | |
0d7e008e SC |
16 | You should have received a copy of the GNU General Public License |
17 | along with GNU CC; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
bc45ade3 | 19 | |
8aa2a305 JW |
20 | /* Contributed by Steve Chamberlain (sac@cygnus.com). |
21 | Improved by Jim Wilson (wilson@cygnus.com). */ | |
bc45ade3 | 22 | |
bc45ade3 | 23 | #include "config.h" |
8aa2a305 JW |
24 | |
25 | #include <stdio.h> | |
26 | ||
bc45ade3 | 27 | #include "rtl.h" |
bc45ade3 | 28 | #include "tree.h" |
bc45ade3 | 29 | #include "flags.h" |
8aa2a305 | 30 | #include "insn-flags.h" |
bc45ade3 | 31 | #include "expr.h" |
8aa2a305 JW |
32 | #include "regs.h" |
33 | #include "hard-reg-set.h" | |
34 | #include "output.h" | |
bc45ade3 | 35 | |
00f8ff66 SC |
36 | #define MSW (TARGET_LITTLE_ENDIAN ? 1 : 0) |
37 | #define LSW (TARGET_LITTLE_ENDIAN ? 0 : 1) | |
38 | ||
20b04867 | 39 | /* ??? The pragma interrupt support will not work for SH3. */ |
8aa2a305 JW |
40 | /* This is set by #pragma interrupt and #pragma trapa, and causes gcc to |
41 | output code for the next function appropriate for an interrupt handler. */ | |
0d7e008e | 42 | int pragma_interrupt; |
bc45ade3 | 43 | |
8aa2a305 JW |
44 | /* This is set by #pragma trapa, and is similar to the above, except that |
45 | the compiler doesn't emit code to preserve all registers. */ | |
46 | static int pragma_trapa; | |
47 | ||
48 | /* This is used for communication between SETUP_INCOMING_VARARGS and | |
49 | sh_expand_prologue. */ | |
bc45ade3 | 50 | int current_function_anonymous_args; |
16bea517 | 51 | |
8aa2a305 JW |
52 | /* Global variables from toplev.c and final.c that are used within, but |
53 | not declared in any header file. */ | |
b9654711 | 54 | extern char *version_string; |
8aa2a305 | 55 | extern int *insn_addresses; |
00f8ff66 | 56 | |
bc45ade3 SC |
57 | /* Global variables for machine-dependent things. */ |
58 | ||
16bea517 JW |
59 | /* Which cpu are we scheduling for. */ |
60 | enum processor_type sh_cpu; | |
61 | ||
bc45ade3 | 62 | /* Saved operands from the last compare to use when we generate an scc |
16bea517 | 63 | or bcc insn. */ |
bc45ade3 SC |
64 | |
65 | rtx sh_compare_op0; | |
66 | rtx sh_compare_op1; | |
67 | ||
68 | /* Provides the class number of the smallest class containing | |
16bea517 | 69 | reg number. */ |
bc45ade3 SC |
70 | |
71 | int regno_reg_class[FIRST_PSEUDO_REGISTER] = | |
72 | { | |
8e87e161 | 73 | R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, |
bc45ade3 SC |
74 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, |
75 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
76 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
8e87e161 SC |
77 | GENERAL_REGS, PR_REGS, T_REGS, NO_REGS, |
78 | MAC_REGS, MAC_REGS, | |
bc45ade3 SC |
79 | }; |
80 | ||
81 | /* Provide reg_class from a letter such as appears in the machine | |
16bea517 | 82 | description. */ |
bc45ade3 SC |
83 | |
84 | enum reg_class reg_class_from_letter[] = | |
85 | { | |
86 | /* a */ NO_REGS, /* b */ NO_REGS, /* c */ NO_REGS, /* d */ NO_REGS, | |
87 | /* e */ NO_REGS, /* f */ NO_REGS, /* g */ NO_REGS, /* h */ NO_REGS, | |
88 | /* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ PR_REGS, | |
89 | /* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS, | |
90 | /* q */ NO_REGS, /* r */ NO_REGS, /* s */ NO_REGS, /* t */ T_REGS, | |
91 | /* u */ NO_REGS, /* v */ NO_REGS, /* w */ NO_REGS, /* x */ MAC_REGS, | |
92 | /* y */ NO_REGS, /* z */ R0_REGS | |
93 | }; | |
b9654711 | 94 | \f |
16bea517 | 95 | /* Print the operand address in x to the stream. */ |
bc45ade3 SC |
96 | |
97 | void | |
98 | print_operand_address (stream, x) | |
99 | FILE *stream; | |
100 | rtx x; | |
101 | { | |
102 | switch (GET_CODE (x)) | |
103 | { | |
104 | case REG: | |
105 | fprintf (stream, "@%s", reg_names[REGNO (x)]); | |
106 | break; | |
8aa2a305 | 107 | |
bc45ade3 SC |
108 | case PLUS: |
109 | { | |
110 | rtx base = XEXP (x, 0); | |
111 | rtx index = XEXP (x, 1); | |
112 | ||
bc45ade3 SC |
113 | switch (GET_CODE (index)) |
114 | { | |
115 | case CONST_INT: | |
8aa2a305 | 116 | fprintf (stream, "@(%d,%s)", INTVAL (index), |
bc45ade3 SC |
117 | reg_names[REGNO (base)]); |
118 | break; | |
119 | ||
120 | case REG: | |
b9654711 SC |
121 | fprintf (stream, "@(r0,%s)", |
122 | reg_names[MAX (REGNO (base), REGNO (index))]); | |
bc45ade3 SC |
123 | break; |
124 | ||
125 | default: | |
b9654711 | 126 | debug_rtx (x); |
bc45ade3 SC |
127 | abort (); |
128 | } | |
129 | } | |
bc45ade3 | 130 | break; |
8aa2a305 | 131 | |
bc45ade3 SC |
132 | case PRE_DEC: |
133 | fprintf (stream, "@-%s", reg_names[REGNO (XEXP (x, 0))]); | |
134 | break; | |
135 | ||
136 | case POST_INC: | |
137 | fprintf (stream, "@%s+", reg_names[REGNO (XEXP (x, 0))]); | |
138 | break; | |
139 | ||
140 | default: | |
141 | output_addr_const (stream, x); | |
142 | break; | |
143 | } | |
144 | } | |
145 | ||
146 | /* Print operand x (an rtx) in assembler syntax to file stream | |
147 | according to modifier code. | |
148 | ||
b9654711 | 149 | '.' print a .s if insn needs delay slot |
d3ae8277 | 150 | '@' print rte or rts depending upon pragma interruptness |
8aa2a305 JW |
151 | '#' output a nop if there is nothing to put in the delay slot |
152 | 'O' print a constant without the # | |
00f8ff66 | 153 | 'R' print the LSW of a dp value - changes if in little endian |
00f8ff66 | 154 | 'S' print the MSW of a dp value - changes if in little endian |
8aa2a305 | 155 | 'T' print the next word of a dp value - same as 'R' in big endian mode. */ |
bc45ade3 SC |
156 | |
157 | void | |
158 | print_operand (stream, x, code) | |
159 | FILE *stream; | |
160 | rtx x; | |
161 | int code; | |
162 | { | |
163 | switch (code) | |
164 | { | |
b9654711 | 165 | case '.': |
79b2746a JW |
166 | if (final_sequence |
167 | && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))) | |
b9654711 SC |
168 | fprintf (stream, ".s"); |
169 | break; | |
d3ae8277 SC |
170 | case '@': |
171 | if (pragma_interrupt) | |
8e87e161 | 172 | fprintf (stream, "rte"); |
d3ae8277 | 173 | else |
8e87e161 | 174 | fprintf (stream, "rts"); |
d3ae8277 | 175 | break; |
bc45ade3 | 176 | case '#': |
16bea517 | 177 | /* Output a nop if there's nothing in the delay slot. */ |
bc45ade3 | 178 | if (dbr_sequence_length () == 0) |
8aa2a305 | 179 | fprintf (stream, "\n\tnop"); |
bc45ade3 | 180 | break; |
b9654711 | 181 | case 'O': |
0d7e008e | 182 | output_addr_const (stream, x); |
bc45ade3 | 183 | break; |
bc45ade3 | 184 | case 'R': |
8aa2a305 JW |
185 | fputs (reg_names[REGNO (x) + LSW], (stream)); |
186 | break; | |
187 | case 'S': | |
188 | fputs (reg_names[REGNO (x) + MSW], (stream)); | |
00f8ff66 SC |
189 | break; |
190 | case 'T': | |
16bea517 | 191 | /* Next word of a double. */ |
bc45ade3 SC |
192 | switch (GET_CODE (x)) |
193 | { | |
194 | case REG: | |
195 | fputs (reg_names[REGNO (x) + 1], (stream)); | |
196 | break; | |
197 | case MEM: | |
8aa2a305 JW |
198 | print_operand_address (stream, |
199 | XEXP (adj_offsettable_operand (x, 4), 0)); | |
bc45ade3 SC |
200 | break; |
201 | } | |
202 | break; | |
bc45ade3 SC |
203 | default: |
204 | switch (GET_CODE (x)) | |
205 | { | |
206 | case REG: | |
207 | fputs (reg_names[REGNO (x)], (stream)); | |
208 | break; | |
209 | case MEM: | |
210 | output_address (XEXP (x, 0)); | |
211 | break; | |
212 | default: | |
213 | fputc ('#', stream); | |
214 | output_addr_const (stream, x); | |
215 | break; | |
bc45ade3 SC |
216 | } |
217 | break; | |
218 | } | |
219 | } | |
bc45ade3 | 220 | \f |
0d7e008e SC |
221 | /* Emit code to perform a block move. Choose the best method. |
222 | ||
223 | OPERANDS[0] is the destination. | |
224 | OPERANDS[1] is the source. | |
225 | OPERANDS[2] is the size. | |
226 | OPERANDS[3] is the alignment safe to use. */ | |
227 | ||
0d7e008e SC |
228 | int |
229 | expand_block_move (operands) | |
230 | rtx *operands; | |
231 | { | |
232 | int align = INTVAL (operands[3]); | |
233 | int constp = (GET_CODE (operands[2]) == CONST_INT); | |
234 | int bytes = (constp ? INTVAL (operands[2]) : 0); | |
0d7e008e | 235 | |
8aa2a305 JW |
236 | /* If it isn't a constant number of bytes, or if it doesn't have 4 byte |
237 | alignment, or if it isn't a multiple of 4 bytes, then fail. */ | |
238 | if (! constp || align < 4 || (bytes % 4 != 0)) | |
d3ae8277 SC |
239 | return 0; |
240 | ||
8aa2a305 | 241 | if (bytes < 64) |
0d7e008e SC |
242 | { |
243 | char entry[30]; | |
244 | tree entry_name; | |
245 | rtx func_addr_rtx; | |
246 | rtx r4 = gen_rtx (REG, SImode, 4); | |
247 | rtx r5 = gen_rtx (REG, SImode, 5); | |
8aa2a305 JW |
248 | |
249 | sprintf (entry, "__movstrSI%d", bytes); | |
0d7e008e SC |
250 | entry_name = get_identifier (entry); |
251 | ||
8aa2a305 JW |
252 | func_addr_rtx |
253 | = copy_to_mode_reg (Pmode, | |
254 | gen_rtx (SYMBOL_REF, Pmode, | |
255 | IDENTIFIER_POINTER (entry_name))); | |
0d7e008e SC |
256 | emit_insn (gen_move_insn (r4, XEXP (operands[0], 0))); |
257 | emit_insn (gen_move_insn (r5, XEXP (operands[1], 0))); | |
258 | emit_insn (gen_block_move_real (func_addr_rtx)); | |
259 | return 1; | |
260 | } | |
8aa2a305 JW |
261 | |
262 | /* This is the same number of bytes as a memcpy call, but to a different | |
263 | less common function name, so this will occasionally use more space. */ | |
264 | if (! TARGET_SMALLCODE) | |
0d7e008e | 265 | { |
0d7e008e SC |
266 | tree entry_name; |
267 | rtx func_addr_rtx; | |
8aa2a305 | 268 | int final_switch, while_loop; |
0d7e008e SC |
269 | rtx r4 = gen_rtx (REG, SImode, 4); |
270 | rtx r5 = gen_rtx (REG, SImode, 5); | |
271 | rtx r6 = gen_rtx (REG, SImode, 6); | |
0d7e008e | 272 | |
8aa2a305 JW |
273 | entry_name = get_identifier ("__movstr"); |
274 | func_addr_rtx | |
275 | = copy_to_mode_reg (Pmode, | |
276 | gen_rtx (SYMBOL_REF, Pmode, | |
277 | IDENTIFIER_POINTER (entry_name))); | |
0d7e008e SC |
278 | emit_insn (gen_move_insn (r4, XEXP (operands[0], 0))); |
279 | emit_insn (gen_move_insn (r5, XEXP (operands[1], 0))); | |
280 | ||
8aa2a305 JW |
281 | /* r6 controls the size of the move. 16 is decremented from it |
282 | for each 64 bytes moved. Then the negative bit left over is used | |
283 | as an index into a list of move instructions. e.g., a 72 byte move | |
284 | would be set up with size(r6) = 14, for one iteration through the | |
285 | big while loop, and a switch of -2 for the last part. */ | |
0d7e008e | 286 | |
8aa2a305 JW |
287 | final_switch = 16 - ((bytes / 4) % 16); |
288 | while_loop = ((bytes / 4) / 16 - 1) * 16; | |
289 | emit_insn (gen_move_insn (r6, GEN_INT (while_loop + final_switch))); | |
290 | emit_insn (gen_block_lump_real (func_addr_rtx)); | |
291 | return 1; | |
0d7e008e | 292 | } |
0d7e008e | 293 | |
d3ae8277 | 294 | return 0; |
0d7e008e SC |
295 | } |
296 | ||
bc45ade3 | 297 | /* Prepare operands for a move define_expand; specifically, one of the |
8aa2a305 | 298 | operands must be in a register. */ |
bc45ade3 | 299 | |
b9654711 | 300 | int |
bc45ade3 SC |
301 | prepare_move_operands (operands, mode) |
302 | rtx operands[]; | |
303 | enum machine_mode mode; | |
304 | { | |
8aa2a305 JW |
305 | /* Copy the source to a register if both operands aren't registers. */ |
306 | if (! reload_in_progress && ! reload_completed | |
307 | && ! register_operand (operands[0], mode) | |
308 | && ! register_operand (operands[1], mode)) | |
309 | operands[1] = copy_to_mode_reg (mode, operands[1]); | |
310 | ||
311 | return 0; | |
312 | } | |
313 | ||
314 | /* Prepare the operands for an scc instruction; make sure that the | |
315 | compare has been done. */ | |
316 | rtx | |
317 | prepare_scc_operands (code) | |
318 | enum rtx_code code; | |
319 | { | |
320 | rtx t_reg = gen_rtx (REG, SImode, T_REG); | |
321 | enum rtx_code oldcode = code; | |
322 | ||
323 | /* First need a compare insn. */ | |
324 | switch (code) | |
bc45ade3 | 325 | { |
8aa2a305 JW |
326 | case NE: |
327 | /* It isn't possible to handle this case. */ | |
328 | abort (); | |
329 | case LT: | |
330 | code = GT; | |
331 | break; | |
332 | case LE: | |
333 | code = GE; | |
334 | break; | |
335 | case LTU: | |
336 | code = GTU; | |
337 | break; | |
338 | case LEU: | |
339 | code = GEU; | |
340 | break; | |
bc45ade3 | 341 | } |
8aa2a305 | 342 | if (code != oldcode) |
b9654711 | 343 | { |
8aa2a305 JW |
344 | rtx tmp = sh_compare_op0; |
345 | sh_compare_op0 = sh_compare_op1; | |
346 | sh_compare_op1 = tmp; | |
0d7e008e | 347 | } |
b9654711 | 348 | |
8aa2a305 JW |
349 | sh_compare_op0 = force_reg (SImode, sh_compare_op0); |
350 | if (code != EQ && code != NE | |
351 | && (sh_compare_op1 != const0_rtx | |
352 | || code == GTU || code == GEU || code == LTU || code == LEU)) | |
353 | sh_compare_op1 = force_reg (SImode, sh_compare_op1); | |
0d7e008e | 354 | |
8aa2a305 JW |
355 | emit_insn (gen_rtx (SET, VOIDmode, t_reg, |
356 | gen_rtx (code, SImode, sh_compare_op0, | |
357 | sh_compare_op1))); | |
0d7e008e | 358 | |
8aa2a305 | 359 | return t_reg; |
bc45ade3 SC |
360 | } |
361 | ||
8aa2a305 JW |
362 | /* Called from the md file, set up the operands of a compare instruction. */ |
363 | ||
364 | void | |
365 | from_compare (operands, code) | |
366 | rtx *operands; | |
8e87e161 | 367 | int code; |
bc45ade3 | 368 | { |
8aa2a305 | 369 | if (code != EQ && code != NE) |
bc45ade3 | 370 | { |
8aa2a305 | 371 | /* Force args into regs, since we can't use constants here. */ |
0d7e008e | 372 | sh_compare_op0 = force_reg (SImode, sh_compare_op0); |
8aa2a305 JW |
373 | if (sh_compare_op1 != const0_rtx |
374 | || code == GTU || code == GEU || code == LTU || code == LEU) | |
22e1ebf1 | 375 | sh_compare_op1 = force_reg (SImode, sh_compare_op1); |
bc45ade3 | 376 | } |
8aa2a305 JW |
377 | operands[1] = sh_compare_op0; |
378 | operands[2] = sh_compare_op1; | |
bc45ade3 SC |
379 | } |
380 | \f | |
16bea517 | 381 | /* Functions to output assembly code. */ |
bc45ade3 | 382 | |
b9654711 | 383 | /* Return a sequence of instructions to perform DI or DF move. |
bc45ade3 | 384 | |
b9654711 | 385 | Since the SH cannot move a DI or DF in one instruction, we have |
16bea517 | 386 | to take care when we see overlapping source and dest registers. */ |
0d7e008e | 387 | |
bc45ade3 | 388 | char * |
0d7e008e SC |
389 | output_movedouble (insn, operands, mode) |
390 | rtx insn; | |
bc45ade3 SC |
391 | rtx operands[]; |
392 | enum machine_mode mode; | |
393 | { | |
b9654711 SC |
394 | rtx dst = operands[0]; |
395 | rtx src = operands[1]; | |
b9654711 | 396 | |
0d7e008e | 397 | if (GET_CODE (dst) == MEM |
16bea517 | 398 | && GET_CODE (XEXP (dst, 0)) == PRE_DEC) |
8aa2a305 JW |
399 | return "mov.l %T1,%0\n\tmov.l %1,%0"; |
400 | ||
b9654711 SC |
401 | if (register_operand (dst, mode) |
402 | && register_operand (src, mode)) | |
bc45ade3 | 403 | { |
b9654711 | 404 | if (REGNO (src) == MACH_REG) |
00f8ff66 | 405 | return "sts mach,%S0\n\tsts macl,%R0"; |
bc45ade3 | 406 | |
8aa2a305 JW |
407 | /* When mov.d r1,r2 do r2->r3 then r1->r2; |
408 | when mov.d r1,r0 do r1->r0 then r2->r1. */ | |
b9654711 SC |
409 | |
410 | if (REGNO (src) + 1 == REGNO (dst)) | |
5325c0fa | 411 | return "mov %T1,%T0\n\tmov %1,%0"; |
b9654711 | 412 | else |
5325c0fa | 413 | return "mov %1,%0\n\tmov %T1,%T0"; |
b9654711 SC |
414 | } |
415 | else if (GET_CODE (src) == CONST_INT) | |
bc45ade3 | 416 | { |
8aa2a305 JW |
417 | if (INTVAL (src) < 0) |
418 | output_asm_insn ("mov #-1,%S0", operands); | |
bc45ade3 | 419 | else |
8aa2a305 | 420 | output_asm_insn ("mov #0,%S0", operands); |
bc45ade3 | 421 | |
8aa2a305 | 422 | return "mov %1,%R0"; |
0d7e008e | 423 | } |
b9654711 | 424 | else if (GET_CODE (src) == MEM) |
bc45ade3 | 425 | { |
8aa2a305 | 426 | int ptrreg = -1; |
b9654711 SC |
427 | int dreg = REGNO (dst); |
428 | rtx inside = XEXP (src, 0); | |
bc45ade3 SC |
429 | |
430 | if (GET_CODE (inside) == REG) | |
8aa2a305 | 431 | ptrreg = REGNO (inside); |
79b2746a JW |
432 | else if (GET_CODE (inside) == SUBREG) |
433 | ptrreg = REGNO (SUBREG_REG (inside)) + SUBREG_WORD (inside); | |
bc45ade3 SC |
434 | else if (GET_CODE (inside) == PLUS) |
435 | { | |
8aa2a305 JW |
436 | ptrreg = REGNO (XEXP (inside, 0)); |
437 | /* ??? A r0+REG address shouldn't be possible here, because it isn't | |
438 | an offsettable address. Unfortunately, offsettable addresses use | |
439 | QImode to check the offset, and a QImode offsettable address | |
440 | requires r0 for the other operand, which is not currently | |
441 | supported, so we can't use the 'o' constraint. | |
442 | Thus we must check for and handle r0+REG addresses here. | |
443 | We punt for now, since this is likely very rare. */ | |
444 | if (GET_CODE (XEXP (inside, 1)) == REG) | |
445 | abort (); | |
bc45ade3 | 446 | } |
0d7e008e | 447 | else if (GET_CODE (inside) == LABEL_REF) |
8aa2a305 | 448 | return "mov.l %1,%0\n\tmov.l %1+4,%T0"; |
8e87e161 | 449 | else if (GET_CODE (inside) == POST_INC) |
8aa2a305 | 450 | return "mov.l %1,%0\n\tmov.l %1,%T0"; |
bc45ade3 SC |
451 | else |
452 | abort (); | |
453 | ||
8aa2a305 JW |
454 | /* Work out the safe way to copy. Copy into the second half first. */ |
455 | if (dreg == ptrreg) | |
456 | return "mov.l %T1,%T0\n\tmov.l %1,%0"; | |
bc45ade3 SC |
457 | } |
458 | ||
00f8ff66 | 459 | return "mov.l %1,%0\n\tmov.l %T1,%T0"; |
bc45ade3 SC |
460 | } |
461 | ||
8aa2a305 JW |
462 | /* Print an instruction which would have gone into a delay slot after |
463 | another instruction, but couldn't because the other instruction expanded | |
464 | into a sequence where putting the slot insn at the end wouldn't work. */ | |
0d7e008e | 465 | |
8aa2a305 JW |
466 | static void |
467 | print_slot (insn) | |
468 | rtx insn; | |
469 | { | |
470 | final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file, optimize, 0, 1); | |
b9654711 | 471 | |
8aa2a305 JW |
472 | INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1; |
473 | } | |
0d7e008e | 474 | |
8aa2a305 JW |
475 | /* We can't tell if we need a register as a scratch for the jump |
476 | until after branch shortening, and then it's too late to allocate a | |
477 | register the 'proper' way. These instruction sequences are rare | |
478 | anyway, so to avoid always using a reg up from our limited set, we'll | |
479 | grab one when we need one on output. */ | |
0d7e008e | 480 | |
8aa2a305 JW |
481 | /* ??? Should fix compiler so that using a clobber scratch in jump |
482 | instructions works, and then this will be unnecessary. */ | |
0d7e008e SC |
483 | |
484 | char * | |
485 | output_far_jump (insn, op) | |
486 | rtx insn; | |
487 | rtx op; | |
488 | { | |
489 | rtx thislab = gen_label_rtx (); | |
490 | ||
8aa2a305 | 491 | /* Output the delay slot insn first if any. */ |
0d7e008e | 492 | if (dbr_sequence_length ()) |
8aa2a305 | 493 | print_slot (final_sequence); |
b9654711 | 494 | |
8aa2a305 JW |
495 | output_asm_insn ("mov.l r13,@-r15", 0); |
496 | output_asm_insn ("mov.l %O0,r13", &thislab); | |
497 | output_asm_insn ("jmp @r13", 0); | |
498 | output_asm_insn ("mov.l @r15+,r13", 0); | |
0d7e008e | 499 | output_asm_insn (".align 2", 0); |
d3ae8277 | 500 | ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (thislab)); |
0d7e008e SC |
501 | output_asm_insn (".long %O0", &op); |
502 | return ""; | |
503 | } | |
bc45ade3 | 504 | |
8aa2a305 JW |
505 | /* Local label counter, used for constants in the pool and inside |
506 | pattern branches. */ | |
507 | ||
508 | static int lf = 100; | |
509 | ||
510 | /* Output code for ordinary branches. */ | |
511 | ||
bc45ade3 | 512 | char * |
8aa2a305 | 513 | output_branch (logic, insn, operands) |
bc45ade3 | 514 | int logic; |
b9654711 | 515 | rtx insn; |
8aa2a305 | 516 | rtx *operands; |
bc45ade3 | 517 | { |
bc45ade3 | 518 | int label = lf++; |
8e87e161 | 519 | |
bc45ade3 SC |
520 | switch (get_attr_length (insn)) |
521 | { | |
522 | case 2: | |
22e1ebf1 JW |
523 | /* A branch with an unfilled delay slot. */ |
524 | case 4: | |
525 | /* Simple branch in range -252..+258 bytes */ | |
b9654711 | 526 | return logic ? "bt%. %l0" : "bf%. %l0"; |
bc45ade3 SC |
527 | |
528 | case 6: | |
22e1ebf1 JW |
529 | /* A branch with an unfilled delay slot. */ |
530 | case 8: | |
16bea517 | 531 | /* Branch in range -4092..+4098 bytes. */ |
b9654711 | 532 | { |
8aa2a305 JW |
533 | /* The call to print_slot will clobber the operands. */ |
534 | rtx op0 = operands[0]; | |
b9654711 | 535 | |
79b2746a JW |
536 | /* If the instruction in the delay slot is annulled (true), then |
537 | there is no delay slot where we can put it now. The only safe | |
538 | place for it is after the label. */ | |
539 | ||
16bea517 | 540 | if (final_sequence) |
b9654711 | 541 | { |
79b2746a JW |
542 | fprintf (asm_out_file, "\tb%c%s\tLF%d\n", logic ? 'f' : 't', |
543 | INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)) | |
544 | ? "" : ".s", label); | |
545 | if (! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))) | |
546 | print_slot (final_sequence); | |
b9654711 | 547 | } |
b9654711 | 548 | else |
8aa2a305 | 549 | fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label); |
b9654711 | 550 | |
8aa2a305 JW |
551 | output_asm_insn ("bra %l0", &op0); |
552 | fprintf (asm_out_file, "\tnop\n"); | |
b9654711 | 553 | fprintf (asm_out_file, "LF%d:\n", label); |
79b2746a JW |
554 | |
555 | if (final_sequence | |
556 | && INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))) | |
557 | print_slot (final_sequence); | |
b9654711 | 558 | } |
bc45ade3 SC |
559 | return ""; |
560 | ||
8aa2a305 JW |
561 | case 16: |
562 | /* A branch with an unfilled delay slot. */ | |
563 | case 18: | |
564 | /* Branches a long way away. */ | |
565 | { | |
566 | /* The call to print_slot will clobber the operands. */ | |
567 | rtx op0 = operands[0]; | |
bc45ade3 | 568 | |
79b2746a JW |
569 | /* If the instruction in the delay slot is annulled (true), then |
570 | there is no delay slot where we can put it now. The only safe | |
571 | place for it is after the label. */ | |
572 | ||
8aa2a305 JW |
573 | if (final_sequence) |
574 | { | |
79b2746a JW |
575 | fprintf (asm_out_file, "\tb%c%s\tLF%d\n", logic ? 'f' : 't', |
576 | INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)) | |
577 | ? "" : ".s", label); | |
578 | if (! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))) | |
579 | print_slot (final_sequence); | |
8aa2a305 JW |
580 | } |
581 | else | |
582 | fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label); | |
bc45ade3 | 583 | |
8aa2a305 JW |
584 | output_far_jump (insn, op0); |
585 | fprintf (asm_out_file, "LF%d:\n", label); | |
79b2746a JW |
586 | |
587 | if (final_sequence | |
588 | && INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))) | |
589 | print_slot (final_sequence); | |
8aa2a305 | 590 | } |
79b2746a | 591 | return ""; |
bc45ade3 | 592 | } |
8aa2a305 | 593 | return "bad"; |
bc45ade3 | 594 | } |
8e87e161 | 595 | \f |
8aa2a305 | 596 | /* A copy of the option structure defined in toplev.c. */ |
bc45ade3 | 597 | |
0d7e008e | 598 | struct option |
bc45ade3 | 599 | { |
0d7e008e SC |
600 | char *string; |
601 | int *variable; | |
602 | int on_value; | |
603 | }; | |
b9654711 | 604 | |
8aa2a305 JW |
605 | /* Output a single output option string NAME to FILE, without generating |
606 | lines longer than MAX. */ | |
607 | ||
0d7e008e SC |
608 | static int |
609 | output_option (file, sep, type, name, indent, pos, max) | |
610 | FILE *file; | |
611 | char *sep; | |
612 | char *type; | |
613 | char *name; | |
614 | char *indent; | |
615 | int pos; | |
616 | int max; | |
617 | { | |
618 | if (strlen (sep) + strlen (type) + strlen (name) + pos > max) | |
bc45ade3 | 619 | { |
0d7e008e SC |
620 | fprintf (file, indent); |
621 | return fprintf (file, "%s%s", type, name); | |
b9654711 | 622 | } |
0d7e008e SC |
623 | return pos + fprintf (file, "%s%s%s", sep, type, name); |
624 | } | |
bc45ade3 | 625 | |
8aa2a305 JW |
626 | /* A copy of the target_switches variable in toplev.c. */ |
627 | ||
0d7e008e SC |
628 | static struct |
629 | { | |
630 | char *name; | |
631 | int value; | |
8aa2a305 | 632 | } m_options[] = TARGET_SWITCHES; |
bc45ade3 | 633 | |
8aa2a305 | 634 | /* Output all options to the assembly language file. */ |
bc45ade3 | 635 | |
0d7e008e SC |
636 | static void |
637 | output_options (file, f_options, f_len, W_options, W_len, | |
638 | pos, max, sep, indent, term) | |
639 | FILE *file; | |
640 | struct option *f_options; | |
641 | struct option *W_options; | |
642 | int f_len, W_len; | |
643 | int pos; | |
644 | int max; | |
645 | char *sep; | |
646 | char *indent; | |
647 | char *term; | |
648 | { | |
649 | register int j; | |
bc45ade3 | 650 | |
0d7e008e SC |
651 | if (optimize) |
652 | pos = output_option (file, sep, "-O", "", indent, pos, max); | |
653 | if (write_symbols != NO_DEBUG) | |
654 | pos = output_option (file, sep, "-g", "", indent, pos, max); | |
0d7e008e SC |
655 | if (profile_flag) |
656 | pos = output_option (file, sep, "-p", "", indent, pos, max); | |
657 | if (profile_block_flag) | |
658 | pos = output_option (file, sep, "-a", "", indent, pos, max); | |
bc45ade3 | 659 | |
0d7e008e SC |
660 | for (j = 0; j < f_len; j++) |
661 | if (*f_options[j].variable == f_options[j].on_value) | |
662 | pos = output_option (file, sep, "-f", f_options[j].string, | |
663 | indent, pos, max); | |
bc45ade3 | 664 | |
0d7e008e SC |
665 | for (j = 0; j < W_len; j++) |
666 | if (*W_options[j].variable == W_options[j].on_value) | |
667 | pos = output_option (file, sep, "-W", W_options[j].string, | |
668 | indent, pos, max); | |
bc45ade3 | 669 | |
0d7e008e SC |
670 | for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++) |
671 | if (m_options[j].name[0] != '\0' | |
672 | && m_options[j].value > 0 | |
673 | && ((m_options[j].value & target_flags) | |
674 | == m_options[j].value)) | |
675 | pos = output_option (file, sep, "-m", m_options[j].name, | |
676 | indent, pos, max); | |
bc45ade3 | 677 | |
0d7e008e | 678 | fprintf (file, term); |
0d7e008e | 679 | } |
b9654711 | 680 | |
8aa2a305 JW |
681 | /* Output to FILE the start of the assembler file. */ |
682 | ||
0d7e008e SC |
683 | void |
684 | output_file_start (file, f_options, f_len, W_options, W_len) | |
685 | FILE *file; | |
686 | struct option *f_options; | |
687 | struct option *W_options; | |
688 | int f_len, W_len; | |
bc45ade3 | 689 | { |
0d7e008e | 690 | register int pos; |
b9654711 | 691 | |
0d7e008e | 692 | output_file_directive (file, main_input_filename); |
b9654711 | 693 | |
0d7e008e SC |
694 | /* Switch to the data section so that the coffsem symbol and the |
695 | gcc2_compiled. symbol aren't in the text section. */ | |
696 | data_section (); | |
b9654711 | 697 | |
00f8ff66 | 698 | pos = fprintf (file, "\n! Hitachi SH cc1 (%s) arguments:", version_string); |
0d7e008e SC |
699 | output_options (file, f_options, f_len, W_options, W_len, |
700 | pos, 75, " ", "\n! ", "\n\n"); | |
8aa2a305 JW |
701 | |
702 | if (TARGET_LITTLE_ENDIAN) | |
703 | fprintf (file, "\t.little\n"); | |
bc45ade3 | 704 | } |
0d7e008e | 705 | \f |
16bea517 | 706 | /* Actual number of instructions used to make a shift by N. */ |
8aa2a305 | 707 | static char ashiftrt_insns[] = |
16bea517 JW |
708 | { 0,1,2,3,4,5,8,8,8,8,8,8,8,8,8,8,2,3,4,5,8,8,8,8,8,8,8,8,8,8,8,2}; |
709 | ||
710 | /* Left shift and logical right shift are the same. */ | |
8aa2a305 | 711 | static char shift_insns[] = |
16bea517 | 712 | { 0,1,1,2,2,3,3,4,1,2,2,3,3,4,3,3,1,2,2,3,3,4,3,3,2,3,3,4,4,4,3,3}; |
8aa2a305 | 713 | |
16bea517 JW |
714 | /* Individual shift amounts needed to get the above length sequences. |
715 | One bit right shifts clobber the T bit, so when possible, put one bit | |
716 | shifts in the middle of the sequence, so the ends are eligible for | |
717 | branch delay slots. */ | |
8aa2a305 | 718 | static short shift_amounts[32][5] = { |
16bea517 JW |
719 | {0}, {1}, {2}, {2, 1}, |
720 | {2, 2}, {2, 1, 2}, {2, 2, 2}, {2, 2, 1, 2}, | |
721 | {8}, {8, 1}, {8, 2}, {8, 1, 2}, | |
722 | {8, 2, 2}, {8, 2, 1, 2}, {8, -2, 8}, {8, -1, 8}, | |
723 | {16}, {16, 1}, {16, 2}, {16, 1, 2}, | |
724 | {16, 2, 2}, {16, 2, 1, 2}, {16, -2, 8}, {16, -1, 8}, | |
725 | {16, 8}, {16, 1, 8}, {16, 8, 2}, {16, 8, 1, 2}, | |
1d3534c0 | 726 | {16, 8, 2, 2}, {16, -1, -2, 16}, {16, -2, 16}, {16, -1, 16}}; |
16bea517 JW |
727 | |
728 | /* This is used in length attributes in sh.md to help compute the length | |
729 | of arbitrary constant shift instructions. */ | |
bc45ade3 | 730 | |
16bea517 JW |
731 | int |
732 | shift_insns_rtx (insn) | |
733 | rtx insn; | |
734 | { | |
735 | rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); | |
736 | int shift_count = INTVAL (XEXP (set_src, 1)); | |
737 | enum rtx_code shift_code = GET_CODE (set_src); | |
00f8ff66 | 738 | |
16bea517 JW |
739 | switch (shift_code) |
740 | { | |
741 | case ASHIFTRT: | |
742 | return ashiftrt_insns[shift_count]; | |
743 | case LSHIFTRT: | |
744 | case ASHIFT: | |
745 | return shift_insns[shift_count]; | |
746 | default: | |
747 | abort(); | |
748 | } | |
749 | } | |
750 | ||
16bea517 | 751 | /* Return the cost of a shift. */ |
bc45ade3 | 752 | |
0d7e008e | 753 | int |
8aa2a305 JW |
754 | shiftcosts (x) |
755 | rtx x; | |
bc45ade3 | 756 | { |
8aa2a305 JW |
757 | int value = INTVAL (XEXP (x, 1)); |
758 | ||
16bea517 | 759 | /* If shift by a non constant, then this will be expensive. */ |
8aa2a305 | 760 | if (GET_CODE (XEXP (x, 1)) != CONST_INT) |
00f8ff66 | 761 | { |
20b04867 JW |
762 | if (TARGET_SH3) |
763 | return 2; | |
764 | /* If not an sh3 then we don't even have an instruction for it. */ | |
00f8ff66 SC |
765 | return 20; |
766 | } | |
bc45ade3 | 767 | |
16bea517 | 768 | /* Otherwise, return the true cost in instructions. */ |
8aa2a305 JW |
769 | if (GET_CODE (x) == ASHIFTRT) |
770 | return ashiftrt_insns[value]; | |
771 | else | |
772 | return shift_insns[value]; | |
0d7e008e | 773 | } |
b9654711 | 774 | |
8aa2a305 JW |
775 | /* Return the cost of an AND operation. */ |
776 | ||
8e87e161 | 777 | int |
8aa2a305 JW |
778 | andcosts (x) |
779 | rtx x; | |
0d7e008e SC |
780 | { |
781 | int i; | |
8aa2a305 | 782 | |
a6f71af5 | 783 | /* Anding with a register is a single cycle and instruction. */ |
8aa2a305 | 784 | if (GET_CODE (XEXP (x, 1)) != CONST_INT) |
a6f71af5 | 785 | return 1; |
8aa2a305 JW |
786 | |
787 | i = INTVAL (XEXP (x, 1)); | |
a6f71af5 | 788 | /* These constants are single cycle extu.[bw] instructions. */ |
0d7e008e | 789 | if (i == 0xff || i == 0xffff) |
a6f71af5 JW |
790 | return 1; |
791 | /* Constants that can be used in an and immediate instruction is a single | |
792 | cycle, but this requires r0, so make it a little more expensive. */ | |
793 | if (CONST_OK_FOR_L (i)) | |
0d7e008e | 794 | return 2; |
a6f71af5 JW |
795 | /* Constants that can be loaded with a mov immediate and an and. |
796 | This case is probably unnecessary. */ | |
0d7e008e | 797 | if (CONST_OK_FOR_I (i)) |
a6f71af5 JW |
798 | return 2; |
799 | /* Any other constants requires a 2 cycle pc-relative load plus an and. | |
800 | This case is probably unnecessary. */ | |
801 | return 3; | |
0d7e008e | 802 | } |
d3ae8277 | 803 | |
16bea517 | 804 | /* Return the cost of a multiply. */ |
0d7e008e | 805 | int |
8aa2a305 JW |
806 | multcosts (x) |
807 | rtx x; | |
0d7e008e SC |
808 | { |
809 | if (TARGET_SH2) | |
d3ae8277 SC |
810 | { |
811 | /* We have a mul insn, so we can never take more than the mul and the | |
a7771f78 | 812 | read of the mac reg, but count more because of the latency and extra |
16bea517 | 813 | reg usage. */ |
d3ae8277 | 814 | if (TARGET_SMALLCODE) |
8e87e161 | 815 | return 2; |
a7771f78 | 816 | return 3; |
d3ae8277 SC |
817 | } |
818 | ||
a7771f78 | 819 | /* If we're aiming at small code, then just count the number of |
16bea517 | 820 | insns in a multiply call sequence. */ |
8e87e161 | 821 | if (TARGET_SMALLCODE) |
8aa2a305 | 822 | return 5; |
d3ae8277 | 823 | |
16bea517 | 824 | /* Otherwise count all the insns in the routine we'd be calling too. */ |
d3ae8277 | 825 | return 20; |
0d7e008e | 826 | } |
b9654711 | 827 | |
16bea517 | 828 | /* Code to expand a shift. */ |
b9654711 | 829 | |
0d7e008e SC |
830 | void |
831 | gen_ashift (type, n, reg) | |
832 | int type; | |
833 | int n; | |
834 | rtx reg; | |
835 | { | |
16bea517 JW |
836 | /* Negative values here come from the shift_amounts array. */ |
837 | if (n < 0) | |
838 | { | |
839 | if (type == ASHIFT) | |
840 | type = LSHIFTRT; | |
841 | else | |
842 | type = ASHIFT; | |
843 | n = -n; | |
844 | } | |
845 | ||
0d7e008e | 846 | switch (type) |
bc45ade3 | 847 | { |
0d7e008e SC |
848 | case ASHIFTRT: |
849 | emit_insn (gen_ashrsi3_k (reg, reg, GEN_INT (n))); | |
850 | break; | |
851 | case LSHIFTRT: | |
16bea517 JW |
852 | if (n == 1) |
853 | emit_insn (gen_lshrsi3_m (reg, reg, GEN_INT (n))); | |
854 | else | |
855 | emit_insn (gen_lshrsi3_k (reg, reg, GEN_INT (n))); | |
0d7e008e SC |
856 | break; |
857 | case ASHIFT: | |
5325c0fa | 858 | emit_insn (gen_ashlsi3_k (reg, reg, GEN_INT (n))); |
0d7e008e | 859 | break; |
bc45ade3 | 860 | } |
bc45ade3 | 861 | } |
bc45ade3 | 862 | |
8aa2a305 JW |
863 | /* Output RTL to split a constant shift into its component SH constant |
864 | shift instructions. */ | |
865 | ||
20b04867 JW |
866 | /* ??? For SH3, should reject constant shifts when slower than loading the |
867 | shift count into a register? */ | |
8aa2a305 | 868 | |
0d7e008e SC |
869 | int |
870 | gen_shifty_op (code, operands) | |
871 | int code; | |
872 | rtx *operands; | |
bc45ade3 | 873 | { |
16bea517 | 874 | int value = INTVAL (operands[2]); |
8aa2a305 | 875 | int max, i; |
00f8ff66 | 876 | |
8aa2a305 | 877 | if (value == 31) |
16bea517 | 878 | { |
8aa2a305 | 879 | if (code == LSHIFTRT) |
0d7e008e | 880 | { |
8aa2a305 JW |
881 | emit_insn (gen_rotlsi3_1 (operands[0], operands[0])); |
882 | emit_insn (gen_movt (operands[0])); | |
883 | return; | |
16bea517 | 884 | } |
8aa2a305 | 885 | else if (code == ASHIFT) |
16bea517 | 886 | { |
8aa2a305 JW |
887 | /* There is a two instruction sequence for 31 bit left shifts, |
888 | but it requires r0. */ | |
889 | if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 0) | |
0d7e008e | 890 | { |
8aa2a305 JW |
891 | emit_insn (gen_andsi3 (operands[0], operands[0], const1_rtx)); |
892 | emit_insn (gen_rotlsi3_31 (operands[0], operands[0])); | |
893 | return; | |
0d7e008e | 894 | } |
16bea517 | 895 | } |
8aa2a305 | 896 | } |
a9f71ad8 | 897 | |
8aa2a305 JW |
898 | max = shift_insns[value]; |
899 | for (i = 0; i < max; i++) | |
900 | gen_ashift (code, shift_amounts[value][i], operands[0]); | |
901 | } | |
902 | ||
903 | /* Output RTL for an arithmetic right shift. */ | |
904 | ||
905 | /* ??? Rewrite to use super-optimizer sequences. */ | |
906 | ||
907 | int | |
908 | expand_ashiftrt (operands) | |
909 | rtx *operands; | |
910 | { | |
911 | rtx wrk; | |
912 | char func[18]; | |
913 | tree func_name; | |
914 | int value; | |
915 | ||
20b04867 JW |
916 | if (TARGET_SH3 && GET_CODE (operands[2]) != CONST_INT) |
917 | { | |
918 | rtx count = copy_to_mode_reg (SImode, operands[2]); | |
919 | emit_insn (gen_negsi2 (count, count)); | |
920 | emit_insn (gen_ashrsi3_d (operands[0], operands[1], count)); | |
921 | return 1; | |
922 | } | |
8aa2a305 JW |
923 | if (GET_CODE (operands[2]) != CONST_INT) |
924 | return 0; | |
925 | ||
926 | value = INTVAL (operands[2]); | |
927 | ||
928 | if (value == 31) | |
929 | { | |
930 | emit_insn (gen_ashrsi2_31 (operands[0], operands[1])); | |
931 | return 1; | |
932 | } | |
933 | else if (value >= 16 && value <= 19) | |
934 | { | |
935 | wrk = gen_reg_rtx (SImode); | |
936 | emit_insn (gen_ashrsi2_16 (wrk, operands[1])); | |
937 | value -= 16; | |
938 | while (value--) | |
939 | gen_ashift (ASHIFTRT, 1, wrk); | |
940 | emit_move_insn (operands[0], wrk); | |
941 | return 1; | |
a9f71ad8 | 942 | } |
8aa2a305 JW |
943 | /* Expand a short sequence inline, longer call a magic routine. */ |
944 | else if (value <= 5) | |
945 | { | |
946 | wrk = gen_reg_rtx (SImode); | |
947 | emit_move_insn (wrk, operands[1]); | |
948 | while (value--) | |
949 | gen_ashift (ASHIFTRT, 1, wrk); | |
950 | emit_move_insn (operands[0], wrk); | |
951 | return 1; | |
952 | } | |
953 | ||
954 | wrk = gen_reg_rtx (Pmode); | |
955 | ||
956 | /* Load the value into an arg reg and call a helper. */ | |
957 | emit_move_insn (gen_rtx (REG, SImode, 4), operands[1]); | |
958 | sprintf (func, "__ashiftrt_r4_%d", value); | |
959 | func_name = get_identifier (func); | |
960 | emit_move_insn (wrk, gen_rtx (SYMBOL_REF, Pmode, | |
961 | IDENTIFIER_POINTER (func_name))); | |
962 | emit_insn (gen_ashrsi3_n (GEN_INT (value), wrk)); | |
963 | emit_move_insn (operands[0], gen_rtx (REG, SImode, 4)); | |
964 | return 1; | |
bc45ade3 | 965 | } |
8aa2a305 JW |
966 | \f |
967 | /* The SH cannot load a large constant into a register, constants have to | |
968 | come from a pc relative load. The reference of a pc relative load | |
969 | instruction must be less than 1k infront of the instruction. This | |
970 | means that we often have to dump a constant inside a function, and | |
971 | generate code to branch around it. | |
bc45ade3 | 972 | |
8aa2a305 JW |
973 | It is important to minimize this, since the branches will slow things |
974 | down and make things bigger. | |
975 | ||
976 | Worst case code looks like: | |
977 | ||
978 | mov.l L1,rn | |
979 | bra L2 | |
980 | nop | |
981 | align | |
982 | L1: .long value | |
983 | L2: | |
984 | .. | |
985 | ||
986 | mov.l L3,rn | |
987 | bra L4 | |
988 | nop | |
989 | align | |
990 | L3: .long value | |
991 | L4: | |
992 | .. | |
993 | ||
994 | We fix this by performing a scan before scheduling, which notices which | |
995 | instructions need to have their operands fetched from the constant table | |
996 | and builds the table. | |
997 | ||
998 | The algorithm is: | |
999 | ||
1000 | scan, find an instruction which needs a pcrel move. Look forward, find the | |
1001 | last barrier which is within MAX_COUNT bytes of the requirement. | |
1002 | If there isn't one, make one. Process all the instructions between | |
1003 | the find and the barrier. | |
1004 | ||
1005 | In the above example, we can tell that L3 is within 1k of L1, so | |
1006 | the first move can be shrunk from the 3 insn+constant sequence into | |
1007 | just 1 insn, and the constant moved to L3 to make: | |
1008 | ||
1009 | mov.l L1,rn | |
1010 | .. | |
1011 | mov.l L3,rn | |
1012 | bra L4 | |
1013 | nop | |
1014 | align | |
1015 | L3:.long value | |
1016 | L4:.long value | |
1017 | ||
1018 | Then the second move becomes the target for the shortening process. */ | |
1019 | ||
1020 | typedef struct | |
1021 | { | |
1022 | rtx value; /* Value in table. */ | |
1023 | rtx label; /* Label of value. */ | |
1024 | enum machine_mode mode; /* Mode of value. */ | |
1025 | } pool_node; | |
1026 | ||
1027 | /* The maximum number of constants that can fit into one pool, since | |
1028 | the pc relative range is 0...1020 bytes and constants are at least 4 | |
1029 | bytes long. */ | |
1030 | ||
1031 | #define MAX_POOL_SIZE (1020/4) | |
1032 | static pool_node pool_vector[MAX_POOL_SIZE]; | |
1033 | static int pool_size; | |
1034 | ||
1035 | /* ??? If we need a constant in HImode which is the truncated value of a | |
1036 | constant we need in SImode, we could combine the two entries thus saving | |
1037 | two bytes. Is this common enough to be worth the effort of implementing | |
1038 | it? */ | |
1039 | ||
1040 | /* ??? This stuff should be done at the same time that we shorten branches. | |
1041 | As it is now, we must assume that all branches are the maximum size, and | |
1042 | this causes us to almost always output constant pools sooner than | |
1043 | necessary. */ | |
1044 | ||
1045 | /* Add a constant to the pool and return its label. */ | |
1046 | ||
1047 | static rtx | |
1048 | add_constant (x, mode) | |
1049 | rtx x; | |
1050 | enum machine_mode mode; | |
0d7e008e SC |
1051 | { |
1052 | int i; | |
8aa2a305 JW |
1053 | rtx lab; |
1054 | ||
1055 | /* First see if we've already got it. */ | |
1056 | for (i = 0; i < pool_size; i++) | |
0d7e008e | 1057 | { |
8aa2a305 JW |
1058 | if (x->code == pool_vector[i].value->code |
1059 | && mode == pool_vector[i].mode) | |
0d7e008e | 1060 | { |
8aa2a305 JW |
1061 | if (x->code == CODE_LABEL) |
1062 | { | |
1063 | if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) | |
1064 | continue; | |
1065 | } | |
1066 | if (rtx_equal_p (x, pool_vector[i].value)) | |
1067 | return pool_vector[i].label; | |
0d7e008e | 1068 | } |
0d7e008e | 1069 | } |
b9654711 | 1070 | |
8aa2a305 JW |
1071 | /* Need a new one. */ |
1072 | pool_vector[pool_size].value = x; | |
1073 | lab = gen_label_rtx (); | |
1074 | pool_vector[pool_size].mode = mode; | |
1075 | pool_vector[pool_size].label = lab; | |
1076 | pool_size++; | |
1077 | return lab; | |
0d7e008e | 1078 | } |
16bea517 JW |
1079 | |
1080 | /* Output the literal table. */ | |
b9654711 | 1081 | |
b9654711 | 1082 | static void |
0d7e008e SC |
1083 | dump_table (scan) |
1084 | rtx scan; | |
b9654711 | 1085 | { |
0d7e008e | 1086 | int i; |
0d7e008e | 1087 | int need_align = 1; |
b9654711 | 1088 | |
16bea517 | 1089 | /* Do two passes, first time dump out the HI sized constants. */ |
b9654711 | 1090 | |
0d7e008e | 1091 | for (i = 0; i < pool_size; i++) |
b9654711 | 1092 | { |
8aa2a305 JW |
1093 | pool_node *p = &pool_vector[i]; |
1094 | ||
0d7e008e SC |
1095 | if (p->mode == HImode) |
1096 | { | |
1097 | if (need_align) | |
1098 | { | |
1099 | scan = emit_insn_after (gen_align_2 (), scan); | |
1100 | need_align = 0; | |
1101 | } | |
1102 | scan = emit_label_after (p->label, scan); | |
1103 | scan = emit_insn_after (gen_consttable_2 (p->value), scan); | |
1104 | } | |
b9654711 | 1105 | } |
8aa2a305 | 1106 | |
0d7e008e | 1107 | need_align = 1; |
b9654711 | 1108 | |
0d7e008e | 1109 | for (i = 0; i < pool_size; i++) |
b9654711 | 1110 | { |
8aa2a305 | 1111 | pool_node *p = &pool_vector[i]; |
b9654711 | 1112 | |
0d7e008e | 1113 | switch (p->mode) |
b9654711 | 1114 | { |
0d7e008e SC |
1115 | case HImode: |
1116 | break; | |
1117 | case SImode: | |
1118 | if (need_align) | |
b9654711 | 1119 | { |
0d7e008e | 1120 | need_align = 0; |
d3ae8277 | 1121 | scan = emit_label_after (gen_label_rtx (), scan); |
0d7e008e | 1122 | scan = emit_insn_after (gen_align_4 (), scan); |
b9654711 | 1123 | } |
0d7e008e SC |
1124 | scan = emit_label_after (p->label, scan); |
1125 | scan = emit_insn_after (gen_consttable_4 (p->value), scan); | |
1126 | break; | |
1127 | case DImode: | |
1128 | if (need_align) | |
1129 | { | |
1130 | need_align = 0; | |
d3ae8277 | 1131 | scan = emit_label_after (gen_label_rtx (), scan); |
0d7e008e SC |
1132 | scan = emit_insn_after (gen_align_4 (), scan); |
1133 | } | |
1134 | scan = emit_label_after (p->label, scan); | |
1135 | scan = emit_insn_after (gen_consttable_8 (p->value), scan); | |
1136 | break; | |
1137 | default: | |
1138 | abort (); | |
1139 | break; | |
b9654711 SC |
1140 | } |
1141 | } | |
b9654711 | 1142 | |
0d7e008e SC |
1143 | scan = emit_insn_after (gen_consttable_end (), scan); |
1144 | scan = emit_barrier_after (scan); | |
1145 | pool_size = 0; | |
1146 | } | |
b9654711 | 1147 | |
8aa2a305 JW |
1148 | /* Return non-zero if constant would be an ok source for a |
1149 | mov.w instead of a mov.l. */ | |
b9654711 | 1150 | |
16bea517 | 1151 | static int |
8aa2a305 | 1152 | hi_const (src) |
0d7e008e | 1153 | rtx src; |
0d7e008e | 1154 | { |
8aa2a305 JW |
1155 | return (GET_CODE (src) == CONST_INT |
1156 | && INTVAL (src) >= -32768 | |
1157 | && INTVAL (src) <= 32767); | |
b9654711 SC |
1158 | } |
1159 | ||
8aa2a305 JW |
1160 | /* Non-zero if the insn is a move instruction which needs to be fixed. */ |
1161 | ||
1162 | /* ??? For a DImode/DFmode moves, we don't need to fix it if each half of the | |
1163 | CONST_DOUBLE input value is CONST_OK_FOR_I. For a SFmode move, we don't | |
1164 | need to fix it if the input value is CONST_OK_FOR_I. */ | |
1165 | ||
1166 | static int | |
1167 | broken_move (insn) | |
1168 | rtx insn; | |
b9654711 | 1169 | { |
8aa2a305 JW |
1170 | if (GET_CODE (insn) == INSN |
1171 | && GET_CODE (PATTERN (insn)) == SET | |
1172 | /* We can load any 8 bit value if we don't care what the high | |
1173 | order bits end up as. */ | |
1174 | && GET_MODE (SET_DEST (PATTERN (insn))) != QImode | |
1175 | && CONSTANT_P (SET_SRC (PATTERN (insn))) | |
1176 | && (GET_CODE (SET_SRC (PATTERN (insn))) != CONST_INT | |
1177 | || ! CONST_OK_FOR_I (INTVAL (SET_SRC (PATTERN (insn)))))) | |
d3ae8277 SC |
1178 | return 1; |
1179 | ||
8aa2a305 | 1180 | return 0; |
b9654711 | 1181 | } |
b9654711 | 1182 | |
8aa2a305 JW |
1183 | /* Find the last barrier from insn FROM which is close enough to hold the |
1184 | constant pool. If we can't find one, then create one near the end of | |
1185 | the range. */ | |
b9654711 | 1186 | |
5325c0fa JW |
1187 | /* ??? It would be good to put constant pool tables between a case jump and |
1188 | the jump table. This fails for two reasons. First, there is no | |
1189 | barrier after the case jump. This is a bug in the casesi pattern. | |
1190 | Second, inserting the table here may break the mova instruction that | |
1191 | loads the jump table address, by moving the jump table too far away. | |
1192 | We fix that problem by never outputting the constant pool between a mova | |
1193 | and its label. */ | |
1194 | ||
8aa2a305 | 1195 | static rtx |
06c386ea SC |
1196 | find_barrier (from) |
1197 | rtx from; | |
b9654711 | 1198 | { |
0d7e008e SC |
1199 | int count_si = 0; |
1200 | int count_hi = 0; | |
1201 | int found_hi = 0; | |
1202 | int found_si = 0; | |
1203 | rtx found_barrier = 0; | |
5325c0fa | 1204 | rtx found_mova = 0; |
8aa2a305 JW |
1205 | |
1206 | /* For HImode: range is 510, add 4 because pc counts from address of | |
1207 | second instruction after this one, subtract 2 for the jump instruction | |
1208 | that we may need to emit before the table. This gives 512. | |
1209 | For SImode: range is 1020, add 4 because pc counts from address of | |
1210 | second instruction after this one, subtract 2 in case pc is 2 byte | |
1211 | aligned, subtract 2 for the jump instruction that we may need to emit | |
1212 | before the table. This gives 1020. */ | |
1213 | while (from && count_si < 1020 && count_hi < 512) | |
0d7e008e SC |
1214 | { |
1215 | int inc; | |
8aa2a305 | 1216 | |
0d7e008e | 1217 | if (GET_CODE (from) == BARRIER) |
8aa2a305 JW |
1218 | found_barrier = from; |
1219 | ||
06c386ea | 1220 | /* Count the length of this insn - we assume that all moves will |
8aa2a305 | 1221 | be 2 bytes long, except the DImode/DFmode movess. */ |
b9654711 | 1222 | |
8aa2a305 | 1223 | if (broken_move (from)) |
0d7e008e SC |
1224 | { |
1225 | rtx src = SET_SRC (PATTERN (from)); | |
8aa2a305 | 1226 | |
0d7e008e SC |
1227 | if (hi_const (src)) |
1228 | found_hi = 1; | |
1229 | else | |
1230 | found_si = 1; | |
06c386ea | 1231 | inc = (GET_MODE_SIZE (GET_MODE (src)) > 4) ? 4 : 2; |
0d7e008e SC |
1232 | } |
1233 | else | |
8aa2a305 | 1234 | inc = get_attr_length (from); |
5325c0fa | 1235 | |
5325c0fa JW |
1236 | if (GET_CODE (from) == INSN |
1237 | && GET_CODE (PATTERN (from)) == SET | |
16bea517 JW |
1238 | && GET_CODE (SET_SRC (PATTERN (from))) == UNSPEC |
1239 | && XINT (SET_SRC (PATTERN (from)), 1) == 1) | |
5325c0fa JW |
1240 | found_mova = from; |
1241 | else if (GET_CODE (from) == JUMP_INSN | |
1242 | && (GET_CODE (PATTERN (from)) == ADDR_VEC | |
1243 | || GET_CODE (PATTERN (from)) == ADDR_DIFF_VEC)) | |
1244 | found_mova = 0; | |
1245 | ||
0d7e008e SC |
1246 | if (found_si) |
1247 | count_si += inc; | |
1248 | if (found_hi) | |
1249 | count_hi += inc; | |
1250 | from = NEXT_INSN (from); | |
1251 | } | |
1252 | ||
5325c0fa JW |
1253 | /* Insert the constant pool table before the mova instruction, to prevent |
1254 | the mova label reference from going out of range. */ | |
1255 | if (found_mova) | |
1256 | from = found_mova; | |
1257 | ||
8aa2a305 | 1258 | if (! found_barrier) |
b9654711 | 1259 | { |
8aa2a305 JW |
1260 | /* We didn't find a barrier in time to dump our stuff, |
1261 | so we'll make one. */ | |
0d7e008e | 1262 | rtx label = gen_label_rtx (); |
8aa2a305 JW |
1263 | |
1264 | /* We went one instruction too far above. */ | |
06c386ea | 1265 | from = PREV_INSN (from); |
8aa2a305 JW |
1266 | /* Walk back to be just before any jump or label. |
1267 | Putting it before a label reduces the number of times the branch | |
1268 | around the constant pool table will be hit. Putting it before | |
1269 | a jump makes it more likely that the bra delay slot will be | |
1270 | filled. */ | |
1271 | while (GET_CODE (from) == JUMP_INSN || GET_CODE (from) == NOTE | |
8e87e161 | 1272 | || GET_CODE (from) == CODE_LABEL) |
8aa2a305 JW |
1273 | from = PREV_INSN (from); |
1274 | ||
0d7e008e SC |
1275 | from = emit_jump_insn_after (gen_jump (label), from); |
1276 | JUMP_LABEL (from) = label; | |
1277 | found_barrier = emit_barrier_after (from); | |
1278 | emit_label_after (label, found_barrier); | |
b9654711 | 1279 | } |
b9654711 | 1280 | |
8aa2a305 | 1281 | return found_barrier; |
0d7e008e | 1282 | } |
b9654711 | 1283 | |
8aa2a305 | 1284 | /* Exported to toplev.c. |
b9654711 | 1285 | |
0d7e008e | 1286 | Scan the function looking for move instructions which have to be changed to |
8aa2a305 | 1287 | pc-relative loads and insert the literal tables. */ |
b9654711 | 1288 | |
0d7e008e SC |
1289 | void |
1290 | machine_dependent_reorg (first) | |
1291 | rtx first; | |
1292 | { | |
1293 | rtx insn; | |
8aa2a305 | 1294 | |
0d7e008e SC |
1295 | for (insn = first; insn; insn = NEXT_INSN (insn)) |
1296 | { | |
1297 | if (broken_move (insn)) | |
1298 | { | |
0d7e008e | 1299 | rtx scan; |
8aa2a305 JW |
1300 | /* Scan ahead looking for a barrier to stick the constant table |
1301 | behind. */ | |
0d7e008e | 1302 | rtx barrier = find_barrier (insn); |
b9654711 | 1303 | |
16bea517 | 1304 | /* Now find all the moves between the points and modify them. */ |
0d7e008e SC |
1305 | for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) |
1306 | { | |
1307 | if (broken_move (scan)) | |
1308 | { | |
1309 | rtx pat = PATTERN (scan); | |
1310 | rtx src = SET_SRC (pat); | |
1311 | rtx dst = SET_DEST (pat); | |
1312 | enum machine_mode mode = GET_MODE (dst); | |
1313 | rtx lab; | |
1314 | rtx newinsn; | |
1315 | rtx newsrc; | |
0d7e008e SC |
1316 | |
1317 | if (mode == SImode && hi_const (src)) | |
1318 | { | |
23ed92ca | 1319 | int offset = 0; |
8aa2a305 | 1320 | |
0d7e008e | 1321 | mode = HImode; |
d3ae8277 | 1322 | while (GET_CODE (dst) == SUBREG) |
23ed92ca JW |
1323 | { |
1324 | offset += SUBREG_WORD (dst); | |
1325 | dst = SUBREG_REG (dst); | |
1326 | } | |
1327 | dst = gen_rtx (REG, HImode, REGNO (dst) + offset); | |
0d7e008e | 1328 | } |
8aa2a305 | 1329 | |
0d7e008e SC |
1330 | lab = add_constant (src, mode); |
1331 | newsrc = gen_rtx (MEM, mode, | |
1332 | gen_rtx (LABEL_REF, VOIDmode, lab)); | |
8aa2a305 JW |
1333 | RTX_UNCHANGING_P (newsrc) = 1; |
1334 | newinsn = emit_insn_after (gen_rtx (SET, VOIDmode, | |
1335 | dst, newsrc), scan); | |
0d7e008e | 1336 | |
0d7e008e SC |
1337 | delete_insn (scan); |
1338 | scan = newinsn; | |
1339 | } | |
1340 | } | |
1341 | dump_table (barrier); | |
1342 | } | |
1343 | } | |
b9654711 SC |
1344 | } |
1345 | ||
8aa2a305 JW |
1346 | /* Dump out instruction addresses, which is useful for debugging the |
1347 | constant pool table stuff. */ | |
1348 | ||
1349 | /* ??? This is unnecessary, and probably should be deleted. This makes | |
1350 | the insn_addresses declaration above unnecessary. */ | |
1351 | ||
1352 | /* ??? The addresses printed by this routine for insns are nonsense for | |
1353 | insns which are inside of a sequence where none of the inner insns have | |
1354 | variable length. This is because the second pass of shorten_branches | |
1355 | does not bother to update them. */ | |
0d7e008e | 1356 | |
8e87e161 | 1357 | void |
8aa2a305 JW |
1358 | final_prescan_insn (insn, opvec, noperands) |
1359 | rtx insn; | |
1360 | rtx *opvec; | |
1361 | int noperands; | |
b9654711 | 1362 | { |
8aa2a305 JW |
1363 | if (TARGET_DUMPISIZE) |
1364 | fprintf (asm_out_file, "\n! at %04x\n", insn_addresses[INSN_UID (insn)]); | |
0d7e008e | 1365 | } |
b9654711 | 1366 | |
8aa2a305 JW |
1367 | /* Dump out any constants accumulated in the final pass. These will |
1368 | will only be labels. */ | |
b9654711 | 1369 | |
8aa2a305 JW |
1370 | char * |
1371 | output_jump_label_table () | |
0d7e008e | 1372 | { |
8aa2a305 JW |
1373 | int i; |
1374 | ||
1375 | if (pool_size) | |
1376 | { | |
1377 | fprintf (asm_out_file, "\t.align 2\n"); | |
1378 | for (i = 0; i < pool_size; i++) | |
1379 | { | |
1380 | pool_node *p = &pool_vector[i]; | |
1381 | ||
1382 | ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", | |
1383 | CODE_LABEL_NUMBER (p->label)); | |
1384 | output_asm_insn (".long %O0", &p->value); | |
1385 | } | |
1386 | pool_size = 0; | |
1387 | } | |
b9654711 | 1388 | |
8aa2a305 JW |
1389 | return ""; |
1390 | } | |
1391 | \f | |
1392 | /* A full frame looks like: | |
16bea517 JW |
1393 | |
1394 | arg-5 | |
1395 | arg-4 | |
1396 | [ if current_function_anonymous_args | |
1397 | arg-3 | |
1398 | arg-2 | |
1399 | arg-1 | |
1400 | arg-0 ] | |
1401 | saved-fp | |
1402 | saved-r10 | |
1403 | saved-r11 | |
1404 | saved-r12 | |
1405 | saved-pr | |
1406 | local-n | |
1407 | .. | |
1408 | local-1 | |
1409 | local-0 <- fp points here. */ | |
8e87e161 | 1410 | |
8aa2a305 JW |
1411 | /* Number of bytes pushed for anonymous args, used to pass information |
1412 | between expand_prologue and expand_epilogue. */ | |
1413 | ||
1414 | static int extra_push; | |
1415 | ||
1416 | /* Adjust the stack and return the number of bytes taken to do it. */ | |
1417 | ||
1418 | static void | |
1419 | output_stack_adjust (size) | |
1420 | int size; | |
1421 | { | |
1422 | if (size) | |
1423 | { | |
1424 | rtx val = GEN_INT (size); | |
1425 | rtx insn; | |
1426 | ||
1427 | if (! CONST_OK_FOR_I (size)) | |
1428 | { | |
1429 | rtx reg = gen_rtx (REG, SImode, 3); | |
1430 | emit_insn (gen_movsi (reg, val)); | |
1431 | val = reg; | |
1432 | } | |
1433 | ||
1434 | insn = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, val); | |
1435 | emit_insn (insn); | |
1436 | } | |
1437 | } | |
1438 | ||
1439 | /* Output RTL to push register RN onto the stack. */ | |
1440 | ||
1441 | static void | |
1442 | push (rn) | |
1443 | int rn; | |
1444 | { | |
1445 | rtx x; | |
1446 | x = emit_insn (gen_push (gen_rtx (REG, SImode, rn))); | |
1447 | REG_NOTES (x) = gen_rtx (EXPR_LIST, REG_INC, | |
1448 | gen_rtx(REG, SImode, STACK_POINTER_REGNUM), 0); | |
1449 | } | |
1450 | ||
1451 | /* Output RTL to pop register RN from the stack. */ | |
1452 | ||
1453 | static void | |
1454 | pop (rn) | |
1455 | int rn; | |
1456 | { | |
1457 | rtx x; | |
1458 | x = emit_insn (gen_pop (gen_rtx (REG, SImode, rn))); | |
1459 | REG_NOTES (x) = gen_rtx (EXPR_LIST, REG_INC, | |
1460 | gen_rtx(REG, SImode, STACK_POINTER_REGNUM), 0); | |
1461 | } | |
1462 | ||
1463 | /* Generate code to push the regs specified in the mask, and return | |
1464 | the number of bytes the insns take. */ | |
1465 | ||
1466 | static void | |
1467 | push_regs (mask) | |
1468 | int mask; | |
1469 | { | |
1470 | int i; | |
1471 | ||
1472 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
1473 | if (mask & (1 << i)) | |
1474 | push (i); | |
1475 | } | |
1476 | ||
1477 | /* Work out the registers which need to be saved, both as a mask and a | |
1478 | count. | |
1479 | ||
1480 | If doing a pragma interrupt function, then push all regs used by the | |
1481 | function, and if we call another function (we can tell by looking at PR), | |
1482 | make sure that all the regs it clobbers are safe too. */ | |
1483 | ||
1484 | static int | |
1485 | calc_live_regs (count_ptr) | |
1486 | int *count_ptr; | |
1487 | { | |
1488 | int reg; | |
1489 | int live_regs_mask = 0; | |
1490 | int count = 0; | |
1491 | ||
1492 | for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++) | |
1493 | { | |
1494 | if (pragma_interrupt && ! pragma_trapa) | |
1495 | { | |
1496 | /* Need to save all the regs ever live. */ | |
1497 | if ((regs_ever_live[reg] | |
1498 | || (call_used_regs[reg] && regs_ever_live[PR_REG])) | |
1499 | && reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM | |
1500 | && reg != T_REG && reg != GBR_REG) | |
1501 | { | |
1502 | live_regs_mask |= 1 << reg; | |
1503 | count++; | |
1504 | } | |
1505 | } | |
1506 | else | |
1507 | { | |
1508 | /* Only push those regs which are used and need to be saved. */ | |
1509 | if (regs_ever_live[reg] && ! call_used_regs[reg]) | |
1510 | { | |
1511 | live_regs_mask |= (1 << reg); | |
1512 | count++; | |
1513 | } | |
1514 | } | |
1515 | } | |
1516 | ||
1517 | *count_ptr = count; | |
1518 | return live_regs_mask; | |
1519 | } | |
1520 | ||
1521 | /* Code to generate prologue and epilogue sequences */ | |
b9654711 SC |
1522 | |
1523 | void | |
1524 | sh_expand_prologue () | |
1525 | { | |
1526 | int live_regs_mask; | |
40d2032b | 1527 | int d, i; |
b9654711 SC |
1528 | live_regs_mask = calc_live_regs (&d); |
1529 | ||
0d7e008e | 1530 | /* We have pretend args if we had an object sent partially in registers |
8aa2a305 | 1531 | and partially on the stack, e.g. a large structure. */ |
0d7e008e | 1532 | output_stack_adjust (-current_function_pretend_args_size); |
b9654711 | 1533 | |
40d2032b JW |
1534 | extra_push = 0; |
1535 | ||
1536 | /* This is set by SETUP_VARARGS to indicate that this is a varargs | |
1537 | routine. Clear it here so that the next function isn't affected. */ | |
b9654711 SC |
1538 | if (current_function_anonymous_args) |
1539 | { | |
40d2032b JW |
1540 | current_function_anonymous_args = 0; |
1541 | ||
16bea517 | 1542 | /* Push arg regs as if they'd been provided by caller in stack. */ |
b9654711 SC |
1543 | for (i = 0; i < NPARM_REGS; i++) |
1544 | { | |
1545 | int rn = NPARM_REGS + FIRST_PARM_REG - i - 1; | |
79b2746a JW |
1546 | if (i > (NPARM_REGS - current_function_args_info |
1547 | - current_function_varargs)) | |
b9654711 SC |
1548 | break; |
1549 | push (rn); | |
b9654711 SC |
1550 | extra_push += 4; |
1551 | } | |
1552 | } | |
0d7e008e SC |
1553 | push_regs (live_regs_mask); |
1554 | output_stack_adjust (-get_frame_size ()); | |
b9654711 SC |
1555 | |
1556 | if (frame_pointer_needed) | |
8aa2a305 | 1557 | emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); |
b9654711 SC |
1558 | } |
1559 | ||
1560 | void | |
1561 | sh_expand_epilogue () | |
1562 | { | |
1563 | int live_regs_mask; | |
40d2032b | 1564 | int d, i; |
b9654711 SC |
1565 | |
1566 | live_regs_mask = calc_live_regs (&d); | |
16bea517 | 1567 | |
b9654711 | 1568 | if (frame_pointer_needed) |
8aa2a305 JW |
1569 | emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx)); |
1570 | ||
0d7e008e | 1571 | output_stack_adjust (get_frame_size ()); |
b9654711 | 1572 | |
16bea517 | 1573 | /* Pop all the registers. */ |
0d7e008e | 1574 | |
b9654711 SC |
1575 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) |
1576 | { | |
1577 | int j = (FIRST_PSEUDO_REGISTER - 1) - i; | |
1578 | if (live_regs_mask & (1 << j)) | |
8aa2a305 | 1579 | pop (j); |
b9654711 | 1580 | } |
b9654711 | 1581 | |
0d7e008e | 1582 | output_stack_adjust (extra_push + current_function_pretend_args_size); |
b9654711 SC |
1583 | } |
1584 | ||
8aa2a305 JW |
1585 | /* Clear variables at function end. */ |
1586 | ||
1587 | void | |
1588 | function_epilogue (stream, size) | |
1589 | FILE *stream; | |
1590 | int size; | |
1591 | { | |
1592 | pragma_interrupt = pragma_trapa = 0; | |
1593 | } | |
1594 | ||
0d7e008e SC |
1595 | /* Define the offset between two registers, one to be eliminated, and |
1596 | the other its replacement, at the start of a routine. */ | |
1597 | ||
1598 | int | |
1599 | initial_elimination_offset (from, to) | |
8e87e161 SC |
1600 | int from; |
1601 | int to; | |
0d7e008e SC |
1602 | { |
1603 | int regs_saved; | |
0d7e008e SC |
1604 | int total_saved_regs_space; |
1605 | int total_auto_space = get_frame_size (); | |
8e87e161 SC |
1606 | |
1607 | calc_live_regs (®s_saved); | |
0d7e008e | 1608 | total_saved_regs_space = (regs_saved) * 4; |
b9654711 | 1609 | |
0d7e008e | 1610 | if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) |
8aa2a305 JW |
1611 | return total_saved_regs_space + total_auto_space; |
1612 | ||
0d7e008e | 1613 | if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) |
8aa2a305 JW |
1614 | return total_saved_regs_space + total_auto_space; |
1615 | ||
1616 | /* Initial gap between fp and sp is 0. */ | |
0d7e008e | 1617 | if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) |
8aa2a305 JW |
1618 | return 0; |
1619 | ||
0d7e008e SC |
1620 | abort (); |
1621 | } | |
8aa2a305 | 1622 | \f |
0d7e008e | 1623 | /* Handle machine specific pragmas to be semi-compatible with Hitachi |
16bea517 | 1624 | compiler. */ |
b9654711 SC |
1625 | |
1626 | int | |
0d7e008e SC |
1627 | handle_pragma (file) |
1628 | FILE *file; | |
b9654711 | 1629 | { |
0d7e008e SC |
1630 | int c; |
1631 | char pbuf[200]; | |
1632 | int psize = 0; | |
b9654711 | 1633 | |
0d7e008e SC |
1634 | c = getc (file); |
1635 | while (c == ' ' || c == '\t') | |
1636 | c = getc (file); | |
1637 | ||
1638 | if (c == '\n' || c == EOF) | |
1639 | return c; | |
1640 | ||
1641 | while (psize < sizeof (pbuf) - 1 && c != '\n') | |
1642 | { | |
1643 | pbuf[psize++] = c; | |
1644 | if (psize == 9 && strncmp (pbuf, "interrupt", 9) == 0) | |
1645 | { | |
1646 | pragma_interrupt = 1; | |
06c386ea | 1647 | return ' '; |
0d7e008e SC |
1648 | } |
1649 | if (psize == 5 && strncmp (pbuf, "trapa", 5) == 0) | |
1650 | { | |
1651 | pragma_interrupt = pragma_trapa = 1; | |
06c386ea | 1652 | return ' '; |
0d7e008e SC |
1653 | } |
1654 | c = getc (file); | |
1655 | } | |
1656 | return c; | |
1657 | } | |
1658 | \f | |
8aa2a305 | 1659 | /* Predicates used by the templates. */ |
0d7e008e | 1660 | |
8aa2a305 JW |
1661 | /* Returns 1 if OP is MACL, MACH or PR. The input must be a REG rtx. |
1662 | Used only in general_movsrc_operand. */ | |
0d7e008e | 1663 | |
8aa2a305 JW |
1664 | int |
1665 | system_reg_operand (op, mode) | |
1666 | rtx op; | |
1667 | enum machine_mode mode; | |
0d7e008e | 1668 | { |
8aa2a305 | 1669 | switch (REGNO (op)) |
0d7e008e | 1670 | { |
8aa2a305 JW |
1671 | case PR_REG: |
1672 | case MACL_REG: | |
1673 | case MACH_REG: | |
1674 | return 1; | |
0d7e008e | 1675 | } |
8aa2a305 | 1676 | return 0; |
0d7e008e | 1677 | } |
0d7e008e SC |
1678 | |
1679 | /* Returns 1 if OP can be source of a simple move operation. | |
1680 | Same as general_operand, but a LABEL_REF is valid, PRE_DEC is | |
16bea517 | 1681 | invalid as are subregs of system registers. */ |
0d7e008e SC |
1682 | |
1683 | int | |
1684 | general_movsrc_operand (op, mode) | |
1685 | rtx op; | |
1686 | enum machine_mode mode; | |
1687 | { | |
06c386ea SC |
1688 | if (GET_CODE (op) == MEM) |
1689 | { | |
1690 | rtx inside = XEXP (op, 0); | |
1691 | if (GET_CODE (inside) == CONST) | |
1692 | inside = XEXP (inside, 0); | |
0d7e008e | 1693 | |
06c386ea SC |
1694 | if (GET_CODE (inside) == LABEL_REF) |
1695 | return 1; | |
8e87e161 | 1696 | |
06c386ea | 1697 | if (GET_CODE (inside) == PLUS |
8aa2a305 JW |
1698 | && GET_CODE (XEXP (inside, 0)) == LABEL_REF |
1699 | && GET_CODE (XEXP (inside, 1)) == CONST_INT) | |
06c386ea | 1700 | return 1; |
16bea517 JW |
1701 | |
1702 | /* Only post inc allowed. */ | |
97f8690b | 1703 | if (GET_CODE (inside) == PRE_DEC) |
06c386ea | 1704 | return 0; |
06c386ea | 1705 | } |
0d7e008e SC |
1706 | |
1707 | if ((mode == QImode || mode == HImode) | |
1708 | && (GET_CODE (op) == SUBREG | |
1709 | && GET_CODE (XEXP (op, 0)) == REG | |
1710 | && system_reg_operand (XEXP (op, 0), mode))) | |
1711 | return 0; | |
1712 | ||
0d7e008e | 1713 | return general_operand (op, mode); |
b9654711 SC |
1714 | } |
1715 | ||
0d7e008e SC |
1716 | /* Returns 1 if OP can be a destination of a move. |
1717 | Same as general_operand, but no preinc allowed. */ | |
1718 | ||
b9654711 | 1719 | int |
0d7e008e SC |
1720 | general_movdst_operand (op, mode) |
1721 | rtx op; | |
1722 | enum machine_mode mode; | |
b9654711 | 1723 | { |
16bea517 | 1724 | /* Only pre dec allowed. */ |
97f8690b | 1725 | if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == POST_INC) |
0d7e008e | 1726 | return 0; |
d3ae8277 | 1727 | |
0d7e008e SC |
1728 | return general_operand (op, mode); |
1729 | } | |
1730 | ||
0d7e008e SC |
1731 | /* Returns 1 if OP is a normal arithmetic register. */ |
1732 | ||
1733 | int | |
1734 | arith_reg_operand (op, mode) | |
1735 | rtx op; | |
1736 | enum machine_mode mode; | |
1737 | { | |
1738 | if (register_operand (op, mode)) | |
1739 | { | |
1740 | if (GET_CODE (op) == REG) | |
1741 | return (REGNO (op) != T_REG | |
07c109c8 JW |
1742 | && REGNO (op) != PR_REG |
1743 | && REGNO (op) != MACH_REG | |
1744 | && REGNO (op) != MACL_REG); | |
0d7e008e SC |
1745 | return 1; |
1746 | } | |
1747 | return 0; | |
1748 | } | |
1749 | ||
0d7e008e SC |
1750 | /* Returns 1 if OP is a valid source operand for an arithmetic insn. */ |
1751 | ||
1752 | int | |
1753 | arith_operand (op, mode) | |
1754 | rtx op; | |
1755 | enum machine_mode mode; | |
1756 | { | |
1757 | if (arith_reg_operand (op, mode)) | |
1758 | return 1; | |
1759 | ||
8aa2a305 JW |
1760 | if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_I (INTVAL (op))) |
1761 | return 1; | |
1762 | ||
0d7e008e SC |
1763 | return 0; |
1764 | } | |
1765 | ||
22e1ebf1 JW |
1766 | /* Returns 1 if OP is a valid source operand for a compare insn. */ |
1767 | ||
1768 | int | |
1769 | arith_reg_or_0_operand (op, mode) | |
1770 | rtx op; | |
1771 | enum machine_mode mode; | |
1772 | { | |
1773 | if (arith_reg_operand (op, mode)) | |
1774 | return 1; | |
1775 | ||
8aa2a305 JW |
1776 | if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_N (INTVAL (op))) |
1777 | return 1; | |
1778 | ||
22e1ebf1 JW |
1779 | return 0; |
1780 | } | |
1781 | ||
16bea517 | 1782 | /* Returns 1 if OP is a valid source operand for a logical operation. */ |
0d7e008e SC |
1783 | |
1784 | int | |
1785 | logical_operand (op, mode) | |
1786 | rtx op; | |
1787 | enum machine_mode mode; | |
1788 | { | |
1789 | if (arith_reg_operand (op, mode)) | |
1790 | return 1; | |
1791 | ||
8aa2a305 JW |
1792 | if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_L (INTVAL (op))) |
1793 | return 1; | |
1794 | ||
0d7e008e | 1795 | return 0; |
b9654711 | 1796 | } |
8aa2a305 | 1797 | \f |
d3ae8277 SC |
1798 | /* Determine where to put an argument to a function. |
1799 | Value is zero to push the argument on the stack, | |
1800 | or a hard register in which to store the argument. | |
1801 | ||
1802 | MODE is the argument's machine mode. | |
1803 | TYPE is the data type of the argument (as a tree). | |
1804 | This is null for libcalls where that information may | |
1805 | not be available. | |
1806 | CUM is a variable of type CUMULATIVE_ARGS which gives info about | |
1807 | the preceding args and about the function being called. | |
1808 | NAMED is nonzero if this argument is a named parameter | |
1809 | (otherwise it is an extra parameter matching an ellipsis). */ | |
1810 | ||
8e87e161 | 1811 | rtx |
d3ae8277 | 1812 | sh_function_arg (cum, mode, type, named) |
8e87e161 SC |
1813 | CUMULATIVE_ARGS cum; |
1814 | enum machine_mode mode; | |
1815 | tree type; | |
1816 | int named; | |
d3ae8277 SC |
1817 | { |
1818 | if (named) | |
1819 | { | |
8aa2a305 | 1820 | int rr = (ROUND_REG (cum, mode)); |
d3ae8277 SC |
1821 | |
1822 | if (rr < NPARM_REGS) | |
8aa2a305 JW |
1823 | return ((type == 0 || ! TREE_ADDRESSABLE (type)) |
1824 | ? gen_rtx (REG, mode, FIRST_PARM_REG + rr) : 0); | |
d3ae8277 SC |
1825 | } |
1826 | return 0; | |
1827 | } | |
1828 | ||
1829 | /* For an arg passed partly in registers and partly in memory, | |
1830 | this is the number of registers used. | |
1831 | For args passed entirely in registers or entirely in memory, zero. | |
1832 | Any arg that starts in the first 4 regs but won't entirely fit in them | |
1833 | needs partial registers on the SH. */ | |
1834 | ||
1835 | int | |
8aa2a305 JW |
1836 | sh_function_arg_partial_nregs (cum, mode, type, named) |
1837 | CUMULATIVE_ARGS cum; | |
1838 | enum machine_mode mode; | |
1839 | tree type; | |
1840 | int named; | |
d3ae8277 | 1841 | { |
8aa2a305 | 1842 | if (cum < NPARM_REGS) |
8e87e161 | 1843 | { |
8aa2a305 JW |
1844 | if ((type == 0 || ! TREE_ADDRESSABLE (type)) |
1845 | && (cum + (mode == BLKmode | |
1846 | ? ROUND_ADVANCE (int_size_in_bytes (type)) | |
1847 | : ROUND_ADVANCE (GET_MODE_SIZE (mode))) - NPARM_REGS > 0)) | |
1848 | return NPARM_REGS - cum; | |
d3ae8277 SC |
1849 | } |
1850 | return 0; | |
1851 | } |