]>
Commit | Line | Data |
---|---|---|
e075ae69 | 1 | /* Subroutines used for code generation on IA-32. |
3aeae608 | 2 | Copyright (C) 1988, 92, 94-98, 1999 Free Software Foundation, Inc. |
2a2ab3f9 JVA |
3 | |
4 | This file is part of GNU CC. | |
5 | ||
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. | |
10 | ||
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. | |
15 | ||
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 | |
97aadbb9 | 18 | the Free Software Foundation, 59 Temple Place - Suite 330, |
32b5b1aa | 19 | Boston, MA 02111-1307, USA. */ |
2a2ab3f9 | 20 | |
0b6b2900 | 21 | #include <setjmp.h> |
2a2ab3f9 | 22 | #include "config.h" |
bb5177ac | 23 | #include "system.h" |
2a2ab3f9 JVA |
24 | #include "rtl.h" |
25 | #include "regs.h" | |
26 | #include "hard-reg-set.h" | |
27 | #include "real.h" | |
28 | #include "insn-config.h" | |
29 | #include "conditions.h" | |
30 | #include "insn-flags.h" | |
31 | #include "output.h" | |
32 | #include "insn-attr.h" | |
33 | #include "tree.h" | |
34 | #include "flags.h" | |
a8ffcc81 | 35 | #include "except.h" |
ecbc4695 | 36 | #include "function.h" |
00c79232 | 37 | #include "recog.h" |
ced8dd8c | 38 | #include "expr.h" |
f103890b | 39 | #include "toplev.h" |
e075ae69 | 40 | #include "basic-block.h" |
1526a060 | 41 | #include "ggc.h" |
2a2ab3f9 | 42 | |
997de79c JVA |
43 | #ifdef EXTRA_CONSTRAINT |
44 | /* If EXTRA_CONSTRAINT is defined, then the 'S' | |
45 | constraint in REG_CLASS_FROM_LETTER will no longer work, and various | |
46 | asm statements that need 'S' for class SIREG will break. */ | |
ad5a6adc RS |
47 | error EXTRA_CONSTRAINT conflicts with S constraint letter |
48 | /* The previous line used to be #error, but some compilers barf | |
49 | even if the conditional was untrue. */ | |
997de79c JVA |
50 | #endif |
51 | ||
8dfe5673 RK |
52 | #ifndef CHECK_STACK_LIMIT |
53 | #define CHECK_STACK_LIMIT -1 | |
54 | #endif | |
55 | ||
32b5b1aa SC |
56 | /* Processor costs (relative to an add) */ |
57 | struct processor_costs i386_cost = { /* 386 specific costs */ | |
e9a25f70 | 58 | 1, /* cost of an add instruction */ |
32b5b1aa SC |
59 | 1, /* cost of a lea instruction */ |
60 | 3, /* variable shift costs */ | |
61 | 2, /* constant shift costs */ | |
62 | 6, /* cost of starting a multiply */ | |
63 | 1, /* cost of multiply per each bit set */ | |
e075ae69 RH |
64 | 23, /* cost of a divide/mod */ |
65 | 15 /* "large" insn */ | |
32b5b1aa SC |
66 | }; |
67 | ||
68 | struct processor_costs i486_cost = { /* 486 specific costs */ | |
69 | 1, /* cost of an add instruction */ | |
70 | 1, /* cost of a lea instruction */ | |
71 | 3, /* variable shift costs */ | |
72 | 2, /* constant shift costs */ | |
73 | 12, /* cost of starting a multiply */ | |
74 | 1, /* cost of multiply per each bit set */ | |
e075ae69 RH |
75 | 40, /* cost of a divide/mod */ |
76 | 15 /* "large" insn */ | |
32b5b1aa SC |
77 | }; |
78 | ||
e5cb57e8 | 79 | struct processor_costs pentium_cost = { |
32b5b1aa SC |
80 | 1, /* cost of an add instruction */ |
81 | 1, /* cost of a lea instruction */ | |
856b07a1 | 82 | 4, /* variable shift costs */ |
e5cb57e8 | 83 | 1, /* constant shift costs */ |
856b07a1 SC |
84 | 11, /* cost of starting a multiply */ |
85 | 0, /* cost of multiply per each bit set */ | |
e075ae69 RH |
86 | 25, /* cost of a divide/mod */ |
87 | 8 /* "large" insn */ | |
32b5b1aa SC |
88 | }; |
89 | ||
856b07a1 SC |
90 | struct processor_costs pentiumpro_cost = { |
91 | 1, /* cost of an add instruction */ | |
92 | 1, /* cost of a lea instruction */ | |
e075ae69 | 93 | 1, /* variable shift costs */ |
856b07a1 | 94 | 1, /* constant shift costs */ |
e075ae69 | 95 | 1, /* cost of starting a multiply */ |
856b07a1 | 96 | 0, /* cost of multiply per each bit set */ |
e075ae69 RH |
97 | 17, /* cost of a divide/mod */ |
98 | 8 /* "large" insn */ | |
856b07a1 SC |
99 | }; |
100 | ||
a269a03c JC |
101 | struct processor_costs k6_cost = { |
102 | 1, /* cost of an add instruction */ | |
e075ae69 | 103 | 2, /* cost of a lea instruction */ |
a269a03c JC |
104 | 1, /* variable shift costs */ |
105 | 1, /* constant shift costs */ | |
73fe76e4 | 106 | 3, /* cost of starting a multiply */ |
a269a03c | 107 | 0, /* cost of multiply per each bit set */ |
e075ae69 RH |
108 | 18, /* cost of a divide/mod */ |
109 | 8 /* "large" insn */ | |
a269a03c JC |
110 | }; |
111 | ||
32b5b1aa SC |
112 | struct processor_costs *ix86_cost = &pentium_cost; |
113 | ||
a269a03c JC |
114 | /* Processor feature/optimization bitmasks. */ |
115 | #define m_386 (1<<PROCESSOR_I386) | |
116 | #define m_486 (1<<PROCESSOR_I486) | |
117 | #define m_PENT (1<<PROCESSOR_PENTIUM) | |
118 | #define m_PPRO (1<<PROCESSOR_PENTIUMPRO) | |
119 | #define m_K6 (1<<PROCESSOR_K6) | |
120 | ||
121 | const int x86_use_leave = m_386 | m_K6; | |
122 | const int x86_push_memory = m_386 | m_K6; | |
123 | const int x86_zero_extend_with_and = m_486 | m_PENT; | |
e075ae69 RH |
124 | const int x86_movx = 0 /* m_386 | m_PPRO | m_K6 */; |
125 | const int x86_double_with_add = ~m_386; | |
a269a03c | 126 | const int x86_use_bit_test = m_386; |
e075ae69 | 127 | const int x86_unroll_strlen = m_486 | m_PENT; |
a269a03c JC |
128 | const int x86_use_q_reg = m_PENT | m_PPRO | m_K6; |
129 | const int x86_use_any_reg = m_486; | |
130 | const int x86_cmove = m_PPRO; | |
e075ae69 RH |
131 | const int x86_deep_branch = m_PPRO | m_K6; |
132 | const int x86_use_sahf = m_PPRO | m_K6; | |
133 | const int x86_partial_reg_stall = m_PPRO; | |
134 | const int x86_use_loop = m_K6; | |
135 | const int x86_use_fiop = ~m_PPRO; | |
136 | const int x86_use_mov0 = m_K6; | |
137 | const int x86_use_cltd = ~(m_PENT | m_K6); | |
138 | const int x86_read_modify_write = ~m_PENT; | |
139 | const int x86_read_modify = ~(m_PENT | m_PPRO); | |
140 | const int x86_split_long_moves = m_PPRO; | |
a269a03c | 141 | |
f64cecad | 142 | #define AT_BP(mode) (gen_rtx_MEM ((mode), frame_pointer_rtx)) |
2a2ab3f9 | 143 | |
e075ae69 RH |
144 | const char * const hi_reg_name[] = HI_REGISTER_NAMES; |
145 | const char * const qi_reg_name[] = QI_REGISTER_NAMES; | |
146 | const char * const qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES; | |
4c0d89b5 RS |
147 | |
148 | /* Array of the smallest class containing reg number REGNO, indexed by | |
149 | REGNO. Used by REGNO_REG_CLASS in i386.h. */ | |
150 | ||
e075ae69 | 151 | enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER] = |
4c0d89b5 RS |
152 | { |
153 | /* ax, dx, cx, bx */ | |
ab408a86 | 154 | AREG, DREG, CREG, BREG, |
4c0d89b5 | 155 | /* si, di, bp, sp */ |
e075ae69 | 156 | SIREG, DIREG, NON_Q_REGS, NON_Q_REGS, |
4c0d89b5 RS |
157 | /* FP registers */ |
158 | FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS, | |
79325812 | 159 | FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, |
4c0d89b5 | 160 | /* arg pointer */ |
e075ae69 RH |
161 | INDEX_REGS, |
162 | /* flags, fpsr */ | |
163 | NO_REGS, NO_REGS | |
4c0d89b5 | 164 | }; |
c572e5ba JVA |
165 | |
166 | /* Test and compare insns in i386.md store the information needed to | |
167 | generate branch and scc insns here. */ | |
168 | ||
e075ae69 RH |
169 | struct rtx_def *ix86_compare_op0 = NULL_RTX; |
170 | struct rtx_def *ix86_compare_op1 = NULL_RTX; | |
f5316dfe | 171 | |
36edd3cc BS |
172 | #define MAX_386_STACK_LOCALS 2 |
173 | ||
174 | /* Define the structure for the machine field in struct function. */ | |
175 | struct machine_function | |
176 | { | |
177 | rtx stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS]; | |
178 | }; | |
179 | ||
180 | static int pic_label_no = 0; | |
181 | ||
182 | #define ix86_stack_locals (current_function->machine->stack_locals) | |
183 | ||
c8c5cb99 SC |
184 | /* which cpu are we scheduling for */ |
185 | enum processor_type ix86_cpu; | |
186 | ||
187 | /* which instruction set architecture to use. */ | |
c942177e | 188 | int ix86_arch; |
c8c5cb99 SC |
189 | |
190 | /* Strings to hold which cpu and instruction set architecture to use. */ | |
9c23aa47 ZW |
191 | const char *ix86_cpu_string; /* for -mcpu=<xxx> */ |
192 | const char *ix86_arch_string; /* for -march=<xxx> */ | |
c8c5cb99 | 193 | |
f5316dfe | 194 | /* Register allocation order */ |
e075ae69 | 195 | const char *ix86_reg_alloc_order; |
f5316dfe MM |
196 | static char regs_allocated[FIRST_PSEUDO_REGISTER]; |
197 | ||
b08de47e | 198 | /* # of registers to use to pass arguments. */ |
e075ae69 | 199 | const char *ix86_regparm_string; |
e9a25f70 | 200 | |
e075ae69 RH |
201 | /* ix86_regparm_string as a number */ |
202 | int ix86_regparm; | |
e9a25f70 JL |
203 | |
204 | /* Alignment to use for loops and jumps: */ | |
205 | ||
206 | /* Power of two alignment for loops. */ | |
e075ae69 | 207 | const char *ix86_align_loops_string; |
e9a25f70 JL |
208 | |
209 | /* Power of two alignment for non-loop jumps. */ | |
e075ae69 | 210 | const char *ix86_align_jumps_string; |
e9a25f70 | 211 | |
3af4bd89 | 212 | /* Power of two alignment for stack boundary in bytes. */ |
e075ae69 | 213 | const char *ix86_preferred_stack_boundary_string; |
3af4bd89 JH |
214 | |
215 | /* Preferred alignment for stack boundary in bits. */ | |
e075ae69 | 216 | int ix86_preferred_stack_boundary; |
3af4bd89 | 217 | |
e9a25f70 | 218 | /* Values 1-5: see jump.c */ |
e075ae69 RH |
219 | int ix86_branch_cost; |
220 | const char *ix86_branch_cost_string; | |
e9a25f70 JL |
221 | |
222 | /* Power of two alignment for functions. */ | |
e075ae69 RH |
223 | int ix86_align_funcs; |
224 | const char *ix86_align_funcs_string; | |
b08de47e | 225 | |
e9a25f70 | 226 | /* Power of two alignment for loops. */ |
e075ae69 | 227 | int ix86_align_loops; |
b08de47e | 228 | |
e9a25f70 | 229 | /* Power of two alignment for non-loop jumps. */ |
e075ae69 RH |
230 | int ix86_align_jumps; |
231 | \f | |
232 | static void output_pic_addr_const PROTO ((FILE *, rtx, int)); | |
233 | static void put_condition_code PROTO ((enum rtx_code, enum machine_mode, | |
234 | int, int, FILE *)); | |
235 | static enum rtx_code unsigned_comparison PROTO ((enum rtx_code code)); | |
236 | static rtx ix86_expand_int_compare PROTO ((enum rtx_code, rtx, rtx)); | |
237 | static rtx ix86_expand_fp_compare PROTO ((enum rtx_code, rtx, rtx, int)); | |
238 | static rtx ix86_expand_compare PROTO ((enum rtx_code, int)); | |
239 | static rtx gen_push PROTO ((rtx)); | |
240 | static int memory_address_length PROTO ((rtx addr)); | |
241 | static int ix86_flags_dependant PROTO ((rtx, rtx, enum attr_type)); | |
242 | static int ix86_agi_dependant PROTO ((rtx, rtx, enum attr_type)); | |
243 | static int ix86_safe_length PROTO ((rtx)); | |
244 | static enum attr_memory ix86_safe_memory PROTO ((rtx)); | |
245 | static enum attr_pent_pair ix86_safe_pent_pair PROTO ((rtx)); | |
246 | static enum attr_ppro_uops ix86_safe_ppro_uops PROTO ((rtx)); | |
247 | static void ix86_dump_ppro_packet PROTO ((FILE *)); | |
248 | static void ix86_reorder_insn PROTO ((rtx *, rtx *)); | |
249 | static rtx * ix86_pent_find_pair PROTO ((rtx *, rtx *, enum attr_pent_pair, | |
250 | rtx)); | |
36edd3cc | 251 | static void ix86_init_machine_status PROTO ((struct function *)); |
1526a060 | 252 | static void ix86_mark_machine_status PROTO ((struct function *)); |
e075ae69 RH |
253 | |
254 | struct ix86_address | |
255 | { | |
256 | rtx base, index, disp; | |
257 | HOST_WIDE_INT scale; | |
258 | }; | |
b08de47e | 259 | |
e075ae69 RH |
260 | static int ix86_decompose_address PARAMS ((rtx, struct ix86_address *)); |
261 | \f | |
f5316dfe MM |
262 | /* Sometimes certain combinations of command options do not make |
263 | sense on a particular target machine. You can define a macro | |
264 | `OVERRIDE_OPTIONS' to take account of this. This macro, if | |
265 | defined, is executed once just after all the command options have | |
266 | been parsed. | |
267 | ||
268 | Don't use this macro to turn on various extra optimizations for | |
269 | `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */ | |
270 | ||
271 | void | |
272 | override_options () | |
273 | { | |
e075ae69 RH |
274 | /* Comes from final.c -- no real reason to change it. */ |
275 | #define MAX_CODE_ALIGN 16 | |
f5316dfe | 276 | |
c8c5cb99 SC |
277 | static struct ptt |
278 | { | |
e075ae69 RH |
279 | struct processor_costs *cost; /* Processor costs */ |
280 | int target_enable; /* Target flags to enable. */ | |
281 | int target_disable; /* Target flags to disable. */ | |
282 | int align_loop; /* Default alignments. */ | |
283 | int align_jump; | |
284 | int align_func; | |
285 | int branch_cost; | |
286 | } | |
287 | const processor_target_table[PROCESSOR_max] = | |
288 | { | |
289 | {&i386_cost, 0, 0, 2, 2, 2, 1}, | |
290 | {&i486_cost, 0, 0, 4, 4, 4, 1}, | |
291 | {&pentium_cost, 0, 0, -4, -4, -4, 1}, | |
292 | {&pentiumpro_cost, 0, 0, 4, -4, 4, 1}, | |
293 | {&k6_cost, 0, 0, -5, -5, 4, 1} | |
294 | }; | |
295 | ||
296 | static struct pta | |
297 | { | |
298 | char *name; /* processor name or nickname. */ | |
299 | enum processor_type processor; | |
300 | } | |
301 | const processor_alias_table[] = | |
302 | { | |
303 | {"i386", PROCESSOR_I386}, | |
304 | {"i486", PROCESSOR_I486}, | |
305 | {"i586", PROCESSOR_PENTIUM}, | |
306 | {"pentium", PROCESSOR_PENTIUM}, | |
307 | {"i686", PROCESSOR_PENTIUMPRO}, | |
308 | {"pentiumpro", PROCESSOR_PENTIUMPRO}, | |
309 | {"ppro", PROCESSOR_PENTIUMPRO}, | |
310 | {"pentium2", PROCESSOR_PENTIUMPRO}, | |
311 | {"p2", PROCESSOR_PENTIUMPRO}, | |
312 | {"k6", PROCESSOR_K6}, | |
3af4bd89 | 313 | }; |
c8c5cb99 | 314 | |
e075ae69 | 315 | int const pta_size = sizeof(processor_alias_table)/sizeof(struct pta); |
c8c5cb99 | 316 | |
f5316dfe MM |
317 | #ifdef SUBTARGET_OVERRIDE_OPTIONS |
318 | SUBTARGET_OVERRIDE_OPTIONS; | |
319 | #endif | |
320 | ||
e075ae69 RH |
321 | ix86_arch = PROCESSOR_PENTIUM; |
322 | ix86_cpu = (enum processor_type) TARGET_CPU_DEFAULT; | |
323 | ||
324 | if (ix86_arch_string != 0) | |
325 | { | |
326 | int i; | |
327 | for (i = 0; i < pta_size; i++) | |
328 | if (! strcmp (ix86_arch_string, processor_alias_table[i].name)) | |
329 | { | |
330 | ix86_arch = processor_alias_table[i].processor; | |
331 | /* Default cpu tuning to the architecture. */ | |
332 | ix86_cpu = ix86_arch; | |
333 | break; | |
334 | } | |
335 | if (i == pta_size) | |
336 | error ("bad value (%s) for -march= switch", ix86_arch_string); | |
337 | } | |
338 | ||
339 | if (ix86_cpu_string != 0) | |
340 | { | |
341 | int i; | |
342 | for (i = 0; i < pta_size; i++) | |
343 | if (! strcmp (ix86_cpu_string, processor_alias_table[i].name)) | |
344 | { | |
345 | ix86_cpu = processor_alias_table[i].processor; | |
346 | break; | |
347 | } | |
348 | if (i == pta_size) | |
349 | error ("bad value (%s) for -mcpu= switch", ix86_cpu_string); | |
350 | } | |
351 | ||
352 | ix86_cost = processor_target_table[ix86_cpu].cost; | |
353 | target_flags |= processor_target_table[ix86_cpu].target_enable; | |
354 | target_flags &= ~processor_target_table[ix86_cpu].target_disable; | |
355 | ||
36edd3cc BS |
356 | /* Arrange to set up i386_stack_locals for all functions. */ |
357 | init_machine_status = ix86_init_machine_status; | |
1526a060 | 358 | mark_machine_status = ix86_mark_machine_status; |
36edd3cc | 359 | |
e9a25f70 | 360 | /* Validate registers in register allocation order. */ |
e075ae69 | 361 | if (ix86_reg_alloc_order) |
f5316dfe | 362 | { |
e075ae69 RH |
363 | int i, ch; |
364 | for (i = 0; (ch = ix86_reg_alloc_order[i]) != '\0'; i++) | |
f5316dfe | 365 | { |
00c79232 | 366 | int regno = 0; |
79325812 | 367 | |
f5316dfe MM |
368 | switch (ch) |
369 | { | |
370 | case 'a': regno = 0; break; | |
371 | case 'd': regno = 1; break; | |
372 | case 'c': regno = 2; break; | |
373 | case 'b': regno = 3; break; | |
374 | case 'S': regno = 4; break; | |
375 | case 'D': regno = 5; break; | |
376 | case 'B': regno = 6; break; | |
377 | ||
378 | default: fatal ("Register '%c' is unknown", ch); | |
379 | } | |
380 | ||
381 | if (regs_allocated[regno]) | |
e9a25f70 | 382 | fatal ("Register '%c' already specified in allocation order", ch); |
f5316dfe MM |
383 | |
384 | regs_allocated[regno] = 1; | |
385 | } | |
386 | } | |
b08de47e | 387 | |
e9a25f70 | 388 | /* Validate -mregparm= value. */ |
e075ae69 | 389 | if (ix86_regparm_string) |
b08de47e | 390 | { |
e075ae69 RH |
391 | ix86_regparm = atoi (ix86_regparm_string); |
392 | if (ix86_regparm < 0 || ix86_regparm > REGPARM_MAX) | |
e9a25f70 | 393 | fatal ("-mregparm=%d is not between 0 and %d", |
e075ae69 | 394 | ix86_regparm, REGPARM_MAX); |
b08de47e MM |
395 | } |
396 | ||
e9a25f70 | 397 | /* Validate -malign-loops= value, or provide default. */ |
e075ae69 RH |
398 | ix86_align_loops = processor_target_table[ix86_cpu].align_loop; |
399 | if (ix86_align_loops_string) | |
b08de47e | 400 | { |
e075ae69 RH |
401 | ix86_align_loops = atoi (ix86_align_loops_string); |
402 | if (ix86_align_loops < 0 || ix86_align_loops > MAX_CODE_ALIGN) | |
b08de47e | 403 | fatal ("-malign-loops=%d is not between 0 and %d", |
e075ae69 | 404 | ix86_align_loops, MAX_CODE_ALIGN); |
b08de47e | 405 | } |
3af4bd89 JH |
406 | |
407 | /* Validate -malign-jumps= value, or provide default. */ | |
e075ae69 RH |
408 | ix86_align_jumps = processor_target_table[ix86_cpu].align_jump; |
409 | if (ix86_align_jumps_string) | |
b08de47e | 410 | { |
e075ae69 RH |
411 | ix86_align_jumps = atoi (ix86_align_jumps_string); |
412 | if (ix86_align_jumps < 0 || ix86_align_jumps > MAX_CODE_ALIGN) | |
b08de47e | 413 | fatal ("-malign-jumps=%d is not between 0 and %d", |
e075ae69 | 414 | ix86_align_jumps, MAX_CODE_ALIGN); |
b08de47e | 415 | } |
b08de47e | 416 | |
e9a25f70 | 417 | /* Validate -malign-functions= value, or provide default. */ |
e075ae69 RH |
418 | ix86_align_funcs = processor_target_table[ix86_cpu].align_func; |
419 | if (ix86_align_funcs_string) | |
b08de47e | 420 | { |
e075ae69 RH |
421 | ix86_align_funcs = atoi (ix86_align_funcs_string); |
422 | if (ix86_align_funcs < 0 || ix86_align_funcs > MAX_CODE_ALIGN) | |
b08de47e | 423 | fatal ("-malign-functions=%d is not between 0 and %d", |
e075ae69 | 424 | ix86_align_funcs, MAX_CODE_ALIGN); |
b08de47e | 425 | } |
3af4bd89 JH |
426 | |
427 | /* Validate -mpreferred_stack_boundary= value, or provide default. | |
428 | The default of 128 bits is for Pentium III's SSE __m128. */ | |
e075ae69 RH |
429 | ix86_preferred_stack_boundary = 128; |
430 | if (ix86_preferred_stack_boundary_string) | |
3af4bd89 | 431 | { |
e075ae69 | 432 | int i = atoi (ix86_preferred_stack_boundary_string); |
3af4bd89 JH |
433 | if (i < 2 || i > 31) |
434 | fatal ("-mpreferred_stack_boundary=%d is not between 2 and 31", i); | |
e075ae69 | 435 | ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT; |
3af4bd89 | 436 | } |
77a989d1 | 437 | |
e9a25f70 | 438 | /* Validate -mbranch-cost= value, or provide default. */ |
e075ae69 RH |
439 | ix86_branch_cost = processor_target_table[ix86_cpu].branch_cost; |
440 | if (ix86_branch_cost_string) | |
804a8ee0 | 441 | { |
e075ae69 RH |
442 | ix86_branch_cost = atoi (ix86_branch_cost_string); |
443 | if (ix86_branch_cost < 0 || ix86_branch_cost > 5) | |
444 | fatal ("-mbranch-cost=%d is not between 0 and 5", | |
445 | ix86_branch_cost); | |
804a8ee0 | 446 | } |
804a8ee0 | 447 | |
e9a25f70 JL |
448 | /* Keep nonleaf frame pointers. */ |
449 | if (TARGET_OMIT_LEAF_FRAME_POINTER) | |
77a989d1 | 450 | flag_omit_frame_pointer = 1; |
e075ae69 RH |
451 | |
452 | /* If we're doing fast math, we don't care about comparison order | |
453 | wrt NaNs. This lets us use a shorter comparison sequence. */ | |
454 | if (flag_fast_math) | |
455 | target_flags &= ~MASK_IEEE_FP; | |
456 | ||
457 | /* If we're planning on using `loop', use it. */ | |
458 | if (TARGET_USE_LOOP && optimize) | |
459 | flag_branch_on_count_reg = 1; | |
f5316dfe MM |
460 | } |
461 | \f | |
462 | /* A C statement (sans semicolon) to choose the order in which to | |
463 | allocate hard registers for pseudo-registers local to a basic | |
464 | block. | |
465 | ||
466 | Store the desired register order in the array `reg_alloc_order'. | |
467 | Element 0 should be the register to allocate first; element 1, the | |
468 | next register; and so on. | |
469 | ||
470 | The macro body should not assume anything about the contents of | |
471 | `reg_alloc_order' before execution of the macro. | |
472 | ||
473 | On most machines, it is not necessary to define this macro. */ | |
474 | ||
475 | void | |
476 | order_regs_for_local_alloc () | |
477 | { | |
00c79232 | 478 | int i, ch, order; |
f5316dfe | 479 | |
e9a25f70 JL |
480 | /* User specified the register allocation order. */ |
481 | ||
e075ae69 | 482 | if (ix86_reg_alloc_order) |
f5316dfe | 483 | { |
e075ae69 | 484 | for (i = order = 0; (ch = ix86_reg_alloc_order[i]) != '\0'; i++) |
f5316dfe | 485 | { |
00c79232 | 486 | int regno = 0; |
79325812 | 487 | |
f5316dfe MM |
488 | switch (ch) |
489 | { | |
490 | case 'a': regno = 0; break; | |
491 | case 'd': regno = 1; break; | |
492 | case 'c': regno = 2; break; | |
493 | case 'b': regno = 3; break; | |
494 | case 'S': regno = 4; break; | |
495 | case 'D': regno = 5; break; | |
496 | case 'B': regno = 6; break; | |
497 | } | |
498 | ||
499 | reg_alloc_order[order++] = regno; | |
500 | } | |
501 | ||
502 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
503 | { | |
e9a25f70 | 504 | if (! regs_allocated[i]) |
f5316dfe MM |
505 | reg_alloc_order[order++] = i; |
506 | } | |
507 | } | |
508 | ||
e9a25f70 | 509 | /* If user did not specify a register allocation order, use natural order. */ |
f5316dfe MM |
510 | else |
511 | { | |
512 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
513 | reg_alloc_order[i] = i; | |
f5316dfe MM |
514 | } |
515 | } | |
32b5b1aa SC |
516 | \f |
517 | void | |
c6aded7c | 518 | optimization_options (level, size) |
32b5b1aa | 519 | int level; |
bb5177ac | 520 | int size ATTRIBUTE_UNUSED; |
32b5b1aa | 521 | { |
e9a25f70 JL |
522 | /* For -O2 and beyond, turn off -fschedule-insns by default. It tends to |
523 | make the problem with not enough registers even worse. */ | |
32b5b1aa SC |
524 | #ifdef INSN_SCHEDULING |
525 | if (level > 1) | |
526 | flag_schedule_insns = 0; | |
527 | #endif | |
528 | } | |
b08de47e | 529 | \f |
e075ae69 RH |
530 | /* Return nonzero if the rtx is known aligned. */ |
531 | /* ??? Unused. */ | |
5bc7cd8e SC |
532 | |
533 | int | |
e075ae69 | 534 | ix86_aligned_p (op) |
5bc7cd8e SC |
535 | rtx op; |
536 | { | |
e075ae69 RH |
537 | struct ix86_address parts; |
538 | ||
e9a25f70 | 539 | /* Registers and immediate operands are always "aligned". */ |
5bc7cd8e SC |
540 | if (GET_CODE (op) != MEM) |
541 | return 1; | |
542 | ||
e9a25f70 | 543 | /* Don't even try to do any aligned optimizations with volatiles. */ |
5bc7cd8e SC |
544 | if (MEM_VOLATILE_P (op)) |
545 | return 0; | |
546 | ||
5bc7cd8e SC |
547 | op = XEXP (op, 0); |
548 | ||
e075ae69 RH |
549 | /* Pushes and pops are only valid on the stack pointer. */ |
550 | if (GET_CODE (op) == PRE_DEC | |
551 | || GET_CODE (op) == POST_INC) | |
552 | return 1; | |
e9a25f70 | 553 | |
e075ae69 RH |
554 | /* Decode the address. */ |
555 | if (! ix86_decompose_address (op, &parts)) | |
556 | abort (); | |
79325812 | 557 | |
e075ae69 RH |
558 | /* Look for some component that isn't known to be aligned. */ |
559 | if (parts.index) | |
560 | { | |
561 | if (parts.scale < 4 | |
562 | && REGNO_POINTER_ALIGN (REGNO (parts.index)) < 4) | |
563 | return 0; | |
564 | } | |
565 | if (parts.base) | |
566 | { | |
567 | if (REGNO_POINTER_ALIGN (REGNO (parts.index)) < 4) | |
568 | return 0; | |
569 | } | |
570 | if (parts.disp) | |
571 | { | |
572 | if (GET_CODE (parts.disp) != CONST_INT | |
573 | || (INTVAL (parts.disp) & 3) != 0) | |
574 | return 0; | |
5bc7cd8e | 575 | } |
e9a25f70 | 576 | |
e075ae69 RH |
577 | /* Didn't find one -- this must be an aligned address. */ |
578 | return 1; | |
5bc7cd8e SC |
579 | } |
580 | \f | |
b08de47e MM |
581 | /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific |
582 | attribute for DECL. The attributes in ATTRIBUTES have previously been | |
583 | assigned to DECL. */ | |
584 | ||
585 | int | |
e075ae69 | 586 | ix86_valid_decl_attribute_p (decl, attributes, identifier, args) |
bb5177ac RL |
587 | tree decl ATTRIBUTE_UNUSED; |
588 | tree attributes ATTRIBUTE_UNUSED; | |
589 | tree identifier ATTRIBUTE_UNUSED; | |
590 | tree args ATTRIBUTE_UNUSED; | |
b08de47e MM |
591 | { |
592 | return 0; | |
593 | } | |
594 | ||
595 | /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific | |
596 | attribute for TYPE. The attributes in ATTRIBUTES have previously been | |
597 | assigned to TYPE. */ | |
598 | ||
599 | int | |
e075ae69 | 600 | ix86_valid_type_attribute_p (type, attributes, identifier, args) |
b08de47e | 601 | tree type; |
bb5177ac | 602 | tree attributes ATTRIBUTE_UNUSED; |
b08de47e MM |
603 | tree identifier; |
604 | tree args; | |
605 | { | |
606 | if (TREE_CODE (type) != FUNCTION_TYPE | |
ac478ac0 | 607 | && TREE_CODE (type) != METHOD_TYPE |
b08de47e MM |
608 | && TREE_CODE (type) != FIELD_DECL |
609 | && TREE_CODE (type) != TYPE_DECL) | |
610 | return 0; | |
611 | ||
612 | /* Stdcall attribute says callee is responsible for popping arguments | |
613 | if they are not variable. */ | |
614 | if (is_attribute_p ("stdcall", identifier)) | |
615 | return (args == NULL_TREE); | |
616 | ||
e9a25f70 | 617 | /* Cdecl attribute says the callee is a normal C declaration. */ |
b08de47e MM |
618 | if (is_attribute_p ("cdecl", identifier)) |
619 | return (args == NULL_TREE); | |
620 | ||
621 | /* Regparm attribute specifies how many integer arguments are to be | |
e9a25f70 | 622 | passed in registers. */ |
b08de47e MM |
623 | if (is_attribute_p ("regparm", identifier)) |
624 | { | |
625 | tree cst; | |
626 | ||
e9a25f70 | 627 | if (! args || TREE_CODE (args) != TREE_LIST |
b08de47e MM |
628 | || TREE_CHAIN (args) != NULL_TREE |
629 | || TREE_VALUE (args) == NULL_TREE) | |
630 | return 0; | |
631 | ||
632 | cst = TREE_VALUE (args); | |
633 | if (TREE_CODE (cst) != INTEGER_CST) | |
634 | return 0; | |
635 | ||
636 | if (TREE_INT_CST_HIGH (cst) != 0 | |
637 | || TREE_INT_CST_LOW (cst) < 0 | |
638 | || TREE_INT_CST_LOW (cst) > REGPARM_MAX) | |
639 | return 0; | |
640 | ||
641 | return 1; | |
642 | } | |
643 | ||
644 | return 0; | |
645 | } | |
646 | ||
647 | /* Return 0 if the attributes for two types are incompatible, 1 if they | |
648 | are compatible, and 2 if they are nearly compatible (which causes a | |
649 | warning to be generated). */ | |
650 | ||
651 | int | |
e075ae69 | 652 | ix86_comp_type_attributes (type1, type2) |
afcfe58c MM |
653 | tree type1; |
654 | tree type2; | |
b08de47e | 655 | { |
afcfe58c MM |
656 | /* Check for mismatch of non-default calling convention. */ |
657 | char *rtdstr = TARGET_RTD ? "cdecl" : "stdcall"; | |
658 | ||
659 | if (TREE_CODE (type1) != FUNCTION_TYPE) | |
660 | return 1; | |
661 | ||
662 | /* Check for mismatched return types (cdecl vs stdcall). */ | |
6093f019 RH |
663 | if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1)) |
664 | != !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2))) | |
afcfe58c | 665 | return 0; |
b08de47e MM |
666 | return 1; |
667 | } | |
b08de47e MM |
668 | \f |
669 | /* Value is the number of bytes of arguments automatically | |
670 | popped when returning from a subroutine call. | |
671 | FUNDECL is the declaration node of the function (as a tree), | |
672 | FUNTYPE is the data type of the function (as a tree), | |
673 | or for a library call it is an identifier node for the subroutine name. | |
674 | SIZE is the number of bytes of arguments passed on the stack. | |
675 | ||
676 | On the 80386, the RTD insn may be used to pop them if the number | |
677 | of args is fixed, but if the number is variable then the caller | |
678 | must pop them all. RTD can't be used for library calls now | |
679 | because the library is compiled with the Unix compiler. | |
680 | Use of RTD is a selectable option, since it is incompatible with | |
681 | standard Unix calling sequences. If the option is not selected, | |
682 | the caller must always pop the args. | |
683 | ||
684 | The attribute stdcall is equivalent to RTD on a per module basis. */ | |
685 | ||
686 | int | |
e075ae69 | 687 | ix86_return_pops_args (fundecl, funtype, size) |
b08de47e MM |
688 | tree fundecl; |
689 | tree funtype; | |
690 | int size; | |
79325812 | 691 | { |
3345ee7d | 692 | int rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE); |
b08de47e | 693 | |
e9a25f70 JL |
694 | /* Cdecl functions override -mrtd, and never pop the stack. */ |
695 | if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) { | |
79325812 | 696 | |
e9a25f70 | 697 | /* Stdcall functions will pop the stack if not variable args. */ |
698cdd84 SC |
698 | if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype))) |
699 | rtd = 1; | |
79325812 | 700 | |
698cdd84 SC |
701 | if (rtd |
702 | && (TYPE_ARG_TYPES (funtype) == NULL_TREE | |
e9a25f70 JL |
703 | || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) |
704 | == void_type_node))) | |
698cdd84 SC |
705 | return size; |
706 | } | |
79325812 | 707 | |
e9a25f70 | 708 | /* Lose any fake structure return argument. */ |
698cdd84 SC |
709 | if (aggregate_value_p (TREE_TYPE (funtype))) |
710 | return GET_MODE_SIZE (Pmode); | |
79325812 | 711 | |
2614aac6 | 712 | return 0; |
b08de47e | 713 | } |
b08de47e MM |
714 | \f |
715 | /* Argument support functions. */ | |
716 | ||
717 | /* Initialize a variable CUM of type CUMULATIVE_ARGS | |
718 | for a call to a function whose data type is FNTYPE. | |
719 | For a library call, FNTYPE is 0. */ | |
720 | ||
721 | void | |
722 | init_cumulative_args (cum, fntype, libname) | |
e9a25f70 | 723 | CUMULATIVE_ARGS *cum; /* Argument info to initialize */ |
b08de47e MM |
724 | tree fntype; /* tree ptr for function decl */ |
725 | rtx libname; /* SYMBOL_REF of library name or 0 */ | |
726 | { | |
727 | static CUMULATIVE_ARGS zero_cum; | |
728 | tree param, next_param; | |
729 | ||
730 | if (TARGET_DEBUG_ARG) | |
731 | { | |
732 | fprintf (stderr, "\ninit_cumulative_args ("); | |
733 | if (fntype) | |
e9a25f70 JL |
734 | fprintf (stderr, "fntype code = %s, ret code = %s", |
735 | tree_code_name[(int) TREE_CODE (fntype)], | |
736 | tree_code_name[(int) TREE_CODE (TREE_TYPE (fntype))]); | |
b08de47e MM |
737 | else |
738 | fprintf (stderr, "no fntype"); | |
739 | ||
740 | if (libname) | |
741 | fprintf (stderr, ", libname = %s", XSTR (libname, 0)); | |
742 | } | |
743 | ||
744 | *cum = zero_cum; | |
745 | ||
746 | /* Set up the number of registers to use for passing arguments. */ | |
e075ae69 | 747 | cum->nregs = ix86_regparm; |
b08de47e MM |
748 | if (fntype) |
749 | { | |
750 | tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype)); | |
e9a25f70 | 751 | |
b08de47e MM |
752 | if (attr) |
753 | cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); | |
754 | } | |
755 | ||
756 | /* Determine if this function has variable arguments. This is | |
757 | indicated by the last argument being 'void_type_mode' if there | |
758 | are no variable arguments. If there are variable arguments, then | |
759 | we won't pass anything in registers */ | |
760 | ||
761 | if (cum->nregs) | |
762 | { | |
763 | for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0; | |
e9a25f70 | 764 | param != 0; param = next_param) |
b08de47e MM |
765 | { |
766 | next_param = TREE_CHAIN (param); | |
e9a25f70 | 767 | if (next_param == 0 && TREE_VALUE (param) != void_type_node) |
b08de47e MM |
768 | cum->nregs = 0; |
769 | } | |
770 | } | |
771 | ||
772 | if (TARGET_DEBUG_ARG) | |
773 | fprintf (stderr, ", nregs=%d )\n", cum->nregs); | |
774 | ||
775 | return; | |
776 | } | |
777 | ||
778 | /* Update the data in CUM to advance over an argument | |
779 | of mode MODE and data type TYPE. | |
780 | (TYPE is null for libcalls where that information may not be available.) */ | |
781 | ||
782 | void | |
783 | function_arg_advance (cum, mode, type, named) | |
784 | CUMULATIVE_ARGS *cum; /* current arg information */ | |
785 | enum machine_mode mode; /* current arg mode */ | |
786 | tree type; /* type of the argument or 0 if lib support */ | |
787 | int named; /* whether or not the argument was named */ | |
788 | { | |
e9a25f70 JL |
789 | int bytes |
790 | = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); | |
b08de47e MM |
791 | int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; |
792 | ||
793 | if (TARGET_DEBUG_ARG) | |
794 | fprintf (stderr, | |
e9a25f70 | 795 | "function_adv (sz=%d, wds=%2d, nregs=%d, mode=%s, named=%d)\n\n", |
b08de47e MM |
796 | words, cum->words, cum->nregs, GET_MODE_NAME (mode), named); |
797 | ||
798 | cum->words += words; | |
799 | cum->nregs -= words; | |
800 | cum->regno += words; | |
801 | ||
802 | if (cum->nregs <= 0) | |
803 | { | |
804 | cum->nregs = 0; | |
805 | cum->regno = 0; | |
806 | } | |
807 | ||
808 | return; | |
809 | } | |
810 | ||
811 | /* Define where to put the arguments to a function. | |
812 | Value is zero to push the argument on the stack, | |
813 | or a hard register in which to store the argument. | |
814 | ||
815 | MODE is the argument's machine mode. | |
816 | TYPE is the data type of the argument (as a tree). | |
817 | This is null for libcalls where that information may | |
818 | not be available. | |
819 | CUM is a variable of type CUMULATIVE_ARGS which gives info about | |
820 | the preceding args and about the function being called. | |
821 | NAMED is nonzero if this argument is a named parameter | |
822 | (otherwise it is an extra parameter matching an ellipsis). */ | |
823 | ||
824 | struct rtx_def * | |
825 | function_arg (cum, mode, type, named) | |
826 | CUMULATIVE_ARGS *cum; /* current arg information */ | |
827 | enum machine_mode mode; /* current arg mode */ | |
828 | tree type; /* type of the argument or 0 if lib support */ | |
829 | int named; /* != 0 for normal args, == 0 for ... args */ | |
830 | { | |
831 | rtx ret = NULL_RTX; | |
e9a25f70 JL |
832 | int bytes |
833 | = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); | |
b08de47e MM |
834 | int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; |
835 | ||
836 | switch (mode) | |
837 | { | |
e9a25f70 JL |
838 | /* For now, pass fp/complex values on the stack. */ |
839 | default: | |
b08de47e MM |
840 | break; |
841 | ||
842 | case BLKmode: | |
843 | case DImode: | |
844 | case SImode: | |
845 | case HImode: | |
846 | case QImode: | |
847 | if (words <= cum->nregs) | |
f64cecad | 848 | ret = gen_rtx_REG (mode, cum->regno); |
b08de47e MM |
849 | break; |
850 | } | |
851 | ||
852 | if (TARGET_DEBUG_ARG) | |
853 | { | |
854 | fprintf (stderr, | |
e9a25f70 | 855 | "function_arg (size=%d, wds=%2d, nregs=%d, mode=%4s, named=%d", |
b08de47e MM |
856 | words, cum->words, cum->nregs, GET_MODE_NAME (mode), named); |
857 | ||
858 | if (ret) | |
859 | fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO(ret) ]); | |
860 | else | |
861 | fprintf (stderr, ", stack"); | |
862 | ||
863 | fprintf (stderr, " )\n"); | |
864 | } | |
865 | ||
866 | return ret; | |
867 | } | |
e075ae69 RH |
868 | \f |
869 | /* Returns 1 if OP is either a symbol reference or a sum of a symbol | |
870 | reference and a constant. */ | |
b08de47e MM |
871 | |
872 | int | |
e075ae69 RH |
873 | symbolic_operand (op, mode) |
874 | register rtx op; | |
875 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
2a2ab3f9 | 876 | { |
e075ae69 | 877 | switch (GET_CODE (op)) |
2a2ab3f9 | 878 | { |
e075ae69 RH |
879 | case SYMBOL_REF: |
880 | case LABEL_REF: | |
881 | return 1; | |
882 | ||
883 | case CONST: | |
884 | op = XEXP (op, 0); | |
885 | if (GET_CODE (op) == SYMBOL_REF | |
886 | || GET_CODE (op) == LABEL_REF | |
887 | || (GET_CODE (op) == UNSPEC | |
888 | && XINT (op, 1) >= 6 | |
889 | && XINT (op, 1) <= 7)) | |
890 | return 1; | |
891 | if (GET_CODE (op) != PLUS | |
892 | || GET_CODE (XEXP (op, 1)) != CONST_INT) | |
893 | return 0; | |
894 | ||
895 | op = XEXP (op, 0); | |
896 | if (GET_CODE (op) == SYMBOL_REF | |
897 | || GET_CODE (op) == LABEL_REF) | |
898 | return 1; | |
899 | /* Only @GOTOFF gets offsets. */ | |
900 | if (GET_CODE (op) != UNSPEC | |
901 | || XINT (op, 1) != 7) | |
902 | return 0; | |
903 | ||
904 | op = XVECEXP (op, 0, 0); | |
905 | if (GET_CODE (op) == SYMBOL_REF | |
906 | || GET_CODE (op) == LABEL_REF) | |
907 | return 1; | |
908 | return 0; | |
909 | ||
910 | default: | |
911 | return 0; | |
2a2ab3f9 JVA |
912 | } |
913 | } | |
2a2ab3f9 | 914 | |
e075ae69 | 915 | /* Return true if the operand contains a @GOT or @GOTOFF reference. */ |
3b3c6a3f | 916 | |
e075ae69 RH |
917 | int |
918 | pic_symbolic_operand (op, mode) | |
919 | register rtx op; | |
920 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
921 | { | |
922 | if (GET_CODE (op) == CONST) | |
2a2ab3f9 | 923 | { |
e075ae69 RH |
924 | op = XEXP (op, 0); |
925 | if (GET_CODE (op) == UNSPEC) | |
926 | return 1; | |
927 | if (GET_CODE (op) != PLUS | |
928 | || GET_CODE (XEXP (op, 1)) != CONST_INT) | |
929 | return 0; | |
930 | op = XEXP (op, 0); | |
931 | if (GET_CODE (op) == UNSPEC) | |
932 | return 1; | |
2a2ab3f9 | 933 | } |
e075ae69 | 934 | return 0; |
2a2ab3f9 | 935 | } |
2a2ab3f9 | 936 | |
e075ae69 RH |
937 | /* Test for a valid operand for a call instruction. |
938 | Don't allow the arg pointer register or virtual regs | |
939 | since they may change into reg + const, which the patterns | |
940 | can't handle yet. */ | |
2a2ab3f9 | 941 | |
e075ae69 RH |
942 | int |
943 | call_insn_operand (op, mode) | |
944 | rtx op; | |
945 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
946 | { | |
947 | if (GET_CODE (op) != MEM) | |
948 | return 0; | |
949 | op = XEXP (op, 0); | |
2a2ab3f9 | 950 | |
e075ae69 RH |
951 | /* Disallow indirect through a virtual register. This leads to |
952 | compiler aborts when trying to eliminate them. */ | |
953 | if (GET_CODE (op) == REG | |
954 | && (op == arg_pointer_rtx | |
955 | || (REGNO (op) >= FIRST_PSEUDO_REGISTER | |
956 | && REGNO (op) <= LAST_VIRTUAL_REGISTER))) | |
957 | return 0; | |
2a2ab3f9 | 958 | |
e075ae69 RH |
959 | /* Otherwise we can allow any general_operand in the address. */ |
960 | return general_operand (op, Pmode); | |
961 | } | |
2a2ab3f9 | 962 | |
e075ae69 RH |
963 | /* Like call_insn_operand but allow (mem (symbol_ref ...)) |
964 | even if pic. */ | |
5f1ec3e6 | 965 | |
e075ae69 RH |
966 | int |
967 | expander_call_insn_operand (op, mode) | |
968 | rtx op; | |
969 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
970 | { | |
971 | if (GET_CODE (op) != MEM) | |
972 | return 0; | |
973 | op = XEXP (op, 0); | |
2a2ab3f9 | 974 | |
e075ae69 RH |
975 | /* Direct symbol references. */ |
976 | if (CONSTANT_ADDRESS_P (op)) | |
977 | return 1; | |
2a2ab3f9 | 978 | |
e075ae69 RH |
979 | /* Disallow indirect through a virtual register. This leads to |
980 | compiler aborts when trying to eliminate them. */ | |
981 | if (GET_CODE (op) == REG | |
982 | && (op == arg_pointer_rtx | |
983 | || (REGNO (op) >= FIRST_PSEUDO_REGISTER | |
984 | && REGNO (op) <= LAST_VIRTUAL_REGISTER))) | |
985 | return 0; | |
2a2ab3f9 | 986 | |
e075ae69 RH |
987 | /* Otherwise we can allow any general_operand in the address. */ |
988 | return general_operand (op, mode); | |
989 | } | |
79325812 | 990 | |
e075ae69 RH |
991 | int |
992 | constant_call_address_operand (op, mode) | |
993 | rtx op; | |
994 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
995 | { | |
996 | return GET_CODE (op) == MEM && CONSTANT_ADDRESS_P (XEXP (op, 0)); | |
997 | } | |
2a2ab3f9 | 998 | |
e075ae69 | 999 | /* Match exactly zero and one. */ |
e9a25f70 | 1000 | |
e075ae69 RH |
1001 | int |
1002 | const0_operand (op, mode) | |
1003 | register rtx op; | |
1004 | enum machine_mode mode; | |
1005 | { | |
1006 | return op == CONST0_RTX (mode); | |
1007 | } | |
e9a25f70 | 1008 | |
e075ae69 RH |
1009 | int |
1010 | const1_operand (op, mode) | |
1011 | register rtx op; | |
1012 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
1013 | { | |
1014 | return op == const1_rtx; | |
1015 | } | |
2a2ab3f9 | 1016 | |
e075ae69 | 1017 | /* Match 2, 4, or 8. Used for leal multiplicands. */ |
e9a25f70 | 1018 | |
e075ae69 RH |
1019 | int |
1020 | const248_operand (op, mode) | |
1021 | register rtx op; | |
1022 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
1023 | { | |
1024 | return (GET_CODE (op) == CONST_INT | |
1025 | && (INTVAL (op) == 2 || INTVAL (op) == 4 || INTVAL (op) == 8)); | |
1026 | } | |
e9a25f70 | 1027 | |
e075ae69 | 1028 | /* True if this is a constant appropriate for an increment or decremenmt. */ |
81fd0956 | 1029 | |
e075ae69 RH |
1030 | int |
1031 | incdec_operand (op, mode) | |
1032 | register rtx op; | |
1033 | enum machine_mode mode; | |
1034 | { | |
1035 | if (op == const1_rtx || op == constm1_rtx) | |
1036 | return 1; | |
1037 | if (GET_CODE (op) != CONST_INT) | |
1038 | return 0; | |
1039 | if (mode == SImode && INTVAL (op) == (HOST_WIDE_INT) 0xffffffff) | |
1040 | return 1; | |
1041 | if (mode == HImode && INTVAL (op) == (HOST_WIDE_INT) 0xffff) | |
1042 | return 1; | |
1043 | if (mode == QImode && INTVAL (op) == (HOST_WIDE_INT) 0xff) | |
1044 | return 1; | |
1045 | return 0; | |
1046 | } | |
2a2ab3f9 | 1047 | |
e075ae69 RH |
1048 | /* Return false if this is the stack pointer, or any other fake |
1049 | register eliminable to the stack pointer. Otherwise, this is | |
1050 | a register operand. | |
2a2ab3f9 | 1051 | |
e075ae69 RH |
1052 | This is used to prevent esp from being used as an index reg. |
1053 | Which would only happen in pathological cases. */ | |
5f1ec3e6 | 1054 | |
e075ae69 RH |
1055 | int |
1056 | reg_no_sp_operand (op, mode) | |
1057 | register rtx op; | |
1058 | enum machine_mode mode; | |
1059 | { | |
1060 | rtx t = op; | |
1061 | if (GET_CODE (t) == SUBREG) | |
1062 | t = SUBREG_REG (t); | |
1063 | if (t == stack_pointer_rtx || t == arg_pointer_rtx) | |
1064 | return 0; | |
2a2ab3f9 | 1065 | |
e075ae69 | 1066 | return register_operand (op, mode); |
2a2ab3f9 | 1067 | } |
b840bfb0 | 1068 | |
e075ae69 | 1069 | /* Return true if op is a Q_REGS class register. */ |
b840bfb0 | 1070 | |
e075ae69 RH |
1071 | int |
1072 | q_regs_operand (op, mode) | |
1073 | register rtx op; | |
1074 | enum machine_mode mode; | |
b840bfb0 | 1075 | { |
e075ae69 RH |
1076 | if (mode != VOIDmode && GET_MODE (op) != mode) |
1077 | return 0; | |
1078 | if (GET_CODE (op) == SUBREG) | |
1079 | op = SUBREG_REG (op); | |
1080 | return QI_REG_P (op); | |
1081 | } | |
b840bfb0 | 1082 | |
e075ae69 | 1083 | /* Return true if op is a NON_Q_REGS class register. */ |
b840bfb0 | 1084 | |
e075ae69 RH |
1085 | int |
1086 | non_q_regs_operand (op, mode) | |
1087 | register rtx op; | |
1088 | enum machine_mode mode; | |
1089 | { | |
1090 | if (mode != VOIDmode && GET_MODE (op) != mode) | |
1091 | return 0; | |
1092 | if (GET_CODE (op) == SUBREG) | |
1093 | op = SUBREG_REG (op); | |
1094 | return NON_QI_REG_P (op); | |
1095 | } | |
b840bfb0 | 1096 | |
e075ae69 RH |
1097 | /* Return 1 if OP is a comparison operator that can use the condition code |
1098 | generated by a logical operation, which characteristicly does not set | |
1099 | overflow or carry. To be used with CCNOmode. */ | |
b840bfb0 | 1100 | |
e075ae69 RH |
1101 | int |
1102 | no_comparison_operator (op, mode) | |
1103 | register rtx op; | |
1104 | enum machine_mode mode; | |
1105 | { | |
1106 | return ((mode == VOIDmode || GET_MODE (op) == mode) | |
1107 | && GET_RTX_CLASS (GET_CODE (op)) == '<' | |
1108 | && GET_CODE (op) != LE | |
1109 | && GET_CODE (op) != GT); | |
1110 | } | |
b840bfb0 | 1111 | |
e075ae69 | 1112 | /* Return 1 if OP is a comparison operator that can be issued by fcmov. */ |
b840bfb0 | 1113 | |
e075ae69 RH |
1114 | int |
1115 | fcmov_comparison_operator (op, mode) | |
1116 | register rtx op; | |
1117 | enum machine_mode mode; | |
1118 | { | |
1119 | return ((mode == VOIDmode || GET_MODE (op) == mode) | |
1120 | && GET_RTX_CLASS (GET_CODE (op)) == '<' | |
1121 | && GET_CODE (op) == unsigned_condition (GET_CODE (op))); | |
1122 | } | |
b840bfb0 | 1123 | |
e075ae69 RH |
1124 | /* Nearly general operand, but accept any const_double, since we wish |
1125 | to be able to drop them into memory rather than have them get pulled | |
1126 | into registers. */ | |
b840bfb0 | 1127 | |
2a2ab3f9 | 1128 | int |
e075ae69 RH |
1129 | cmp_fp_expander_operand (op, mode) |
1130 | register rtx op; | |
1131 | enum machine_mode mode; | |
2a2ab3f9 | 1132 | { |
e075ae69 | 1133 | if (mode != VOIDmode && mode != GET_MODE (op)) |
0b6b2900 | 1134 | return 0; |
e075ae69 | 1135 | if (GET_CODE (op) == CONST_DOUBLE) |
2a2ab3f9 | 1136 | return 1; |
e075ae69 | 1137 | return general_operand (op, mode); |
2a2ab3f9 JVA |
1138 | } |
1139 | ||
e075ae69 | 1140 | /* Match an SI or HImode register for a zero_extract. */ |
2a2ab3f9 JVA |
1141 | |
1142 | int | |
e075ae69 | 1143 | ext_register_operand (op, mode) |
2a2ab3f9 | 1144 | register rtx op; |
bb5177ac | 1145 | enum machine_mode mode ATTRIBUTE_UNUSED; |
2a2ab3f9 | 1146 | { |
e075ae69 RH |
1147 | if (GET_MODE (op) != SImode && GET_MODE (op) != HImode) |
1148 | return 0; | |
1149 | return register_operand (op, VOIDmode); | |
1150 | } | |
1151 | ||
1152 | /* Return 1 if this is a valid binary floating-point operation. | |
1153 | OP is the expression matched, and MODE is its mode. */ | |
1154 | ||
1155 | int | |
1156 | binary_fp_operator (op, mode) | |
1157 | register rtx op; | |
1158 | enum machine_mode mode; | |
1159 | { | |
1160 | if (mode != VOIDmode && mode != GET_MODE (op)) | |
1161 | return 0; | |
1162 | ||
2a2ab3f9 JVA |
1163 | switch (GET_CODE (op)) |
1164 | { | |
e075ae69 RH |
1165 | case PLUS: |
1166 | case MINUS: | |
1167 | case MULT: | |
1168 | case DIV: | |
1169 | return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT; | |
e9a25f70 | 1170 | |
2a2ab3f9 JVA |
1171 | default: |
1172 | return 0; | |
1173 | } | |
1174 | } | |
fee2770d | 1175 | |
e075ae69 RH |
1176 | int |
1177 | mult_operator(op, mode) | |
1178 | register rtx op; | |
1179 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
1180 | { | |
1181 | return GET_CODE (op) == MULT; | |
1182 | } | |
1183 | ||
1184 | int | |
1185 | div_operator(op, mode) | |
1186 | register rtx op; | |
1187 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
1188 | { | |
1189 | return GET_CODE (op) == DIV; | |
1190 | } | |
0a726ef1 JL |
1191 | |
1192 | int | |
e075ae69 RH |
1193 | arith_or_logical_operator (op, mode) |
1194 | rtx op; | |
1195 | enum machine_mode mode; | |
0a726ef1 | 1196 | { |
e075ae69 RH |
1197 | return ((mode == VOIDmode || GET_MODE (op) == mode) |
1198 | && (GET_RTX_CLASS (GET_CODE (op)) == 'c' | |
1199 | || GET_RTX_CLASS (GET_CODE (op)) == '2')); | |
0a726ef1 JL |
1200 | } |
1201 | ||
e075ae69 | 1202 | /* Returns 1 if OP is memory operand with a displacement. */ |
fee2770d RS |
1203 | |
1204 | int | |
e075ae69 RH |
1205 | memory_displacement_operand (op, mode) |
1206 | register rtx op; | |
1207 | enum machine_mode mode; | |
4f2c8ebb | 1208 | { |
e075ae69 | 1209 | struct ix86_address parts; |
e9a25f70 | 1210 | |
e075ae69 RH |
1211 | if (! memory_operand (op, mode)) |
1212 | return 0; | |
1213 | ||
1214 | if (! ix86_decompose_address (XEXP (op, 0), &parts)) | |
1215 | abort (); | |
1216 | ||
1217 | return parts.disp != NULL_RTX; | |
4f2c8ebb RS |
1218 | } |
1219 | ||
e075ae69 RH |
1220 | /* To avoid problems when jump re-emits comparisons like testqi_ext_0, |
1221 | re-recognize the operand to avoid a copy_to_mode_reg that will fail. | |
1222 | ||
1223 | ??? It seems likely that this will only work because cmpsi is an | |
1224 | expander, and no actual insns use this. */ | |
4f2c8ebb RS |
1225 | |
1226 | int | |
e075ae69 RH |
1227 | cmpsi_operand (op, mode) |
1228 | rtx op; | |
1229 | enum machine_mode mode; | |
fee2770d | 1230 | { |
e075ae69 RH |
1231 | if (general_operand (op, mode)) |
1232 | return 1; | |
1233 | ||
1234 | if (GET_CODE (op) == AND | |
1235 | && GET_MODE (op) == SImode | |
1236 | && GET_CODE (XEXP (op, 0)) == ZERO_EXTRACT | |
1237 | && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT | |
1238 | && GET_CODE (XEXP (XEXP (op, 0), 2)) == CONST_INT | |
1239 | && INTVAL (XEXP (XEXP (op, 0), 1)) == 8 | |
1240 | && INTVAL (XEXP (XEXP (op, 0), 2)) == 8 | |
1241 | && GET_CODE (XEXP (op, 1)) == CONST_INT) | |
fee2770d | 1242 | return 1; |
e9a25f70 | 1243 | |
fee2770d RS |
1244 | return 0; |
1245 | } | |
d784886d | 1246 | |
e075ae69 RH |
1247 | /* Returns 1 if OP is memory operand that can not be represented by the |
1248 | modRM array. */ | |
d784886d RK |
1249 | |
1250 | int | |
e075ae69 | 1251 | long_memory_operand (op, mode) |
d784886d RK |
1252 | register rtx op; |
1253 | enum machine_mode mode; | |
1254 | { | |
e075ae69 | 1255 | if (! memory_operand (op, mode)) |
d784886d RK |
1256 | return 0; |
1257 | ||
e075ae69 | 1258 | return memory_address_length (op) != 0; |
d784886d | 1259 | } |
e075ae69 RH |
1260 | \f |
1261 | /* Return true if the constant is something that can be loaded with | |
1262 | a special instruction. Only handle 0.0 and 1.0; others are less | |
1263 | worthwhile. */ | |
57dbca5e BS |
1264 | |
1265 | int | |
e075ae69 RH |
1266 | standard_80387_constant_p (x) |
1267 | rtx x; | |
57dbca5e | 1268 | { |
e075ae69 RH |
1269 | if (GET_CODE (x) != CONST_DOUBLE) |
1270 | return -1; | |
1271 | ||
1272 | #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) | |
1273 | { | |
1274 | REAL_VALUE_TYPE d; | |
1275 | jmp_buf handler; | |
1276 | int is0, is1; | |
1277 | ||
1278 | if (setjmp (handler)) | |
1279 | return 0; | |
1280 | ||
1281 | set_float_handler (handler); | |
1282 | REAL_VALUE_FROM_CONST_DOUBLE (d, x); | |
1283 | is0 = REAL_VALUES_EQUAL (d, dconst0) && !REAL_VALUE_MINUS_ZERO (d); | |
1284 | is1 = REAL_VALUES_EQUAL (d, dconst1); | |
1285 | set_float_handler (NULL_PTR); | |
1286 | ||
1287 | if (is0) | |
1288 | return 1; | |
1289 | ||
1290 | if (is1) | |
1291 | return 2; | |
1292 | ||
1293 | /* Note that on the 80387, other constants, such as pi, | |
1294 | are much slower to load as standard constants | |
1295 | than to load from doubles in memory! */ | |
1296 | /* ??? Not true on K6: all constants are equal cost. */ | |
1297 | } | |
1298 | #endif | |
1299 | ||
1300 | return 0; | |
57dbca5e BS |
1301 | } |
1302 | ||
2a2ab3f9 JVA |
1303 | /* Returns 1 if OP contains a symbol reference */ |
1304 | ||
1305 | int | |
1306 | symbolic_reference_mentioned_p (op) | |
1307 | rtx op; | |
1308 | { | |
6f7d635c | 1309 | register const char *fmt; |
2a2ab3f9 JVA |
1310 | register int i; |
1311 | ||
1312 | if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) | |
1313 | return 1; | |
1314 | ||
1315 | fmt = GET_RTX_FORMAT (GET_CODE (op)); | |
1316 | for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) | |
1317 | { | |
1318 | if (fmt[i] == 'E') | |
1319 | { | |
1320 | register int j; | |
1321 | ||
1322 | for (j = XVECLEN (op, i) - 1; j >= 0; j--) | |
1323 | if (symbolic_reference_mentioned_p (XVECEXP (op, i, j))) | |
1324 | return 1; | |
1325 | } | |
e9a25f70 | 1326 | |
2a2ab3f9 JVA |
1327 | else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i))) |
1328 | return 1; | |
1329 | } | |
1330 | ||
1331 | return 0; | |
1332 | } | |
e075ae69 RH |
1333 | |
1334 | /* Return 1 if it is appropriate to emit `ret' instructions in the | |
1335 | body of a function. Do this only if the epilogue is simple, needing a | |
1336 | couple of insns. Prior to reloading, we can't tell how many registers | |
1337 | must be saved, so return 0 then. Return 0 if there is no frame | |
1338 | marker to de-allocate. | |
1339 | ||
1340 | If NON_SAVING_SETJMP is defined and true, then it is not possible | |
1341 | for the epilogue to be simple, so return 0. This is a special case | |
1342 | since NON_SAVING_SETJMP will not cause regs_ever_live to change | |
1343 | until final, but jump_optimize may need to know sooner if a | |
1344 | `return' is OK. */ | |
32b5b1aa SC |
1345 | |
1346 | int | |
e075ae69 | 1347 | ix86_can_use_return_insn_p () |
32b5b1aa | 1348 | { |
e075ae69 RH |
1349 | int regno; |
1350 | int nregs = 0; | |
1351 | int reglimit = (frame_pointer_needed | |
1352 | ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); | |
1353 | int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table | |
1354 | || current_function_uses_const_pool); | |
32b5b1aa | 1355 | |
e075ae69 RH |
1356 | #ifdef NON_SAVING_SETJMP |
1357 | if (NON_SAVING_SETJMP && current_function_calls_setjmp) | |
1358 | return 0; | |
1359 | #endif | |
32b5b1aa | 1360 | |
e075ae69 RH |
1361 | if (! reload_completed) |
1362 | return 0; | |
32b5b1aa | 1363 | |
e075ae69 RH |
1364 | for (regno = reglimit - 1; regno >= 0; regno--) |
1365 | if ((regs_ever_live[regno] && ! call_used_regs[regno]) | |
1366 | || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) | |
1367 | nregs++; | |
0afeb08a | 1368 | |
e075ae69 RH |
1369 | return nregs == 0 || ! frame_pointer_needed; |
1370 | } | |
1371 | \f | |
1372 | static char pic_label_name[32]; | |
1373 | static int pic_label_output; | |
e9a25f70 | 1374 | |
e075ae69 RH |
1375 | /* This function generates code for -fpic that loads %ebx with |
1376 | the return address of the caller and then returns. */ | |
1377 | ||
1378 | void | |
1379 | asm_output_function_prefix (file, name) | |
1380 | FILE *file; | |
1381 | char *name ATTRIBUTE_UNUSED; | |
1382 | { | |
1383 | rtx xops[2]; | |
1384 | int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table | |
1385 | || current_function_uses_const_pool); | |
1386 | xops[0] = pic_offset_table_rtx; | |
1387 | xops[1] = stack_pointer_rtx; | |
32b5b1aa | 1388 | |
e075ae69 RH |
1389 | /* Deep branch prediction favors having a return for every call. */ |
1390 | if (pic_reg_used && TARGET_DEEP_BRANCH_PREDICTION) | |
32b5b1aa | 1391 | { |
e075ae69 RH |
1392 | if (!pic_label_output) |
1393 | { | |
1394 | /* This used to call ASM_DECLARE_FUNCTION_NAME() but since it's an | |
1395 | internal (non-global) label that's being emitted, it didn't make | |
1396 | sense to have .type information for local labels. This caused | |
1397 | the SCO OpenServer 5.0.4 ELF assembler grief (why are you giving | |
1398 | me debug info for a label that you're declaring non-global?) this | |
1399 | was changed to call ASM_OUTPUT_LABEL() instead. */ | |
32b5b1aa | 1400 | |
e075ae69 | 1401 | ASM_OUTPUT_LABEL (file, pic_label_name); |
e9a25f70 | 1402 | |
e075ae69 RH |
1403 | xops[1] = gen_rtx_MEM (SImode, xops[1]); |
1404 | output_asm_insn ("mov{l}\t{%1, %0|%0, %1}", xops); | |
1405 | output_asm_insn ("ret", xops); | |
0afeb08a | 1406 | |
e075ae69 | 1407 | pic_label_output = 1; |
32b5b1aa | 1408 | } |
32b5b1aa | 1409 | } |
32b5b1aa | 1410 | } |
32b5b1aa | 1411 | |
e075ae69 RH |
1412 | void |
1413 | load_pic_register () | |
32b5b1aa | 1414 | { |
e075ae69 | 1415 | rtx gotsym, pclab; |
32b5b1aa | 1416 | |
e075ae69 | 1417 | gotsym = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); |
32b5b1aa | 1418 | |
e075ae69 | 1419 | if (TARGET_DEEP_BRANCH_PREDICTION) |
32b5b1aa | 1420 | { |
e075ae69 RH |
1421 | if (pic_label_name[0] == '\0') |
1422 | ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", 0); | |
1423 | pclab = gen_rtx_MEM (QImode, gen_rtx_SYMBOL_REF (Pmode, pic_label_name)); | |
32b5b1aa | 1424 | } |
e075ae69 | 1425 | else |
e5cb57e8 | 1426 | { |
e075ae69 | 1427 | pclab = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ()); |
e5cb57e8 | 1428 | } |
e5cb57e8 | 1429 | |
e075ae69 | 1430 | emit_insn (gen_prologue_get_pc (pic_offset_table_rtx, pclab)); |
2a2ab3f9 | 1431 | |
e075ae69 RH |
1432 | if (! TARGET_DEEP_BRANCH_PREDICTION) |
1433 | emit_insn (gen_popsi1 (pic_offset_table_rtx)); | |
79325812 | 1434 | |
e075ae69 | 1435 | emit_insn (gen_prologue_set_got (pic_offset_table_rtx, gotsym, pclab)); |
e9a25f70 | 1436 | } |
8dfe5673 | 1437 | |
e075ae69 | 1438 | /* Generate an SImode "push" pattern for input ARG. */ |
e9a25f70 | 1439 | |
e075ae69 RH |
1440 | static rtx |
1441 | gen_push (arg) | |
1442 | rtx arg; | |
e9a25f70 | 1443 | { |
c5c76735 JL |
1444 | return gen_rtx_SET (VOIDmode, |
1445 | gen_rtx_MEM (SImode, | |
1446 | gen_rtx_PRE_DEC (SImode, | |
1447 | stack_pointer_rtx)), | |
1448 | arg); | |
e9a25f70 JL |
1449 | } |
1450 | ||
65954bd8 JL |
1451 | /* Compute the size of local storage taking into consideration the |
1452 | desired stack alignment which is to be maintained. Also determine | |
1453 | the number of registers saved below the local storage. */ | |
1454 | ||
1455 | HOST_WIDE_INT | |
1456 | ix86_compute_frame_size (size, nregs_on_stack) | |
1457 | HOST_WIDE_INT size; | |
1458 | int *nregs_on_stack; | |
1459 | { | |
1460 | int limit; | |
1461 | int nregs; | |
1462 | int regno; | |
1463 | int padding; | |
1464 | int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table | |
1465 | || current_function_uses_const_pool); | |
1466 | HOST_WIDE_INT total_size; | |
1467 | ||
1468 | limit = frame_pointer_needed | |
1469 | ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM; | |
1470 | ||
1471 | nregs = 0; | |
1472 | ||
1473 | for (regno = limit - 1; regno >= 0; regno--) | |
1474 | if ((regs_ever_live[regno] && ! call_used_regs[regno]) | |
1475 | || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) | |
1476 | nregs++; | |
1477 | ||
1478 | padding = 0; | |
1479 | total_size = size + (nregs * UNITS_PER_WORD); | |
1480 | ||
1481 | #ifdef PREFERRED_STACK_BOUNDARY | |
1482 | { | |
1483 | int offset; | |
1484 | int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; | |
1485 | ||
1486 | offset = 4; | |
1487 | if (frame_pointer_needed) | |
1488 | offset += UNITS_PER_WORD; | |
1489 | ||
1490 | total_size += offset; | |
1491 | ||
1492 | padding = ((total_size + preferred_alignment - 1) | |
1493 | & -preferred_alignment) - total_size; | |
1494 | ||
1495 | if (padding < (((offset + preferred_alignment - 1) | |
1496 | & -preferred_alignment) - offset)) | |
1497 | padding += preferred_alignment; | |
54ff41b7 JW |
1498 | |
1499 | /* Don't bother aligning the stack of a leaf function | |
1500 | which doesn't allocate any stack slots. */ | |
1501 | if (size == 0 && current_function_is_leaf) | |
1502 | padding = 0; | |
65954bd8 JL |
1503 | } |
1504 | #endif | |
1505 | ||
1506 | if (nregs_on_stack) | |
1507 | *nregs_on_stack = nregs; | |
1508 | ||
1509 | return size + padding; | |
1510 | } | |
1511 | ||
e075ae69 RH |
1512 | /* Expand the prologue into a bunch of separate insns. */ |
1513 | ||
1514 | void | |
1515 | ix86_expand_prologue () | |
2a2ab3f9 JVA |
1516 | { |
1517 | register int regno; | |
1518 | int limit; | |
aae75261 JVA |
1519 | int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table |
1520 | || current_function_uses_const_pool); | |
65954bd8 | 1521 | HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *)0); |
469ac993 | 1522 | rtx insn; |
79325812 | 1523 | |
e075ae69 RH |
1524 | /* Note: AT&T enter does NOT have reversed args. Enter is probably |
1525 | slower on all targets. Also sdb doesn't like it. */ | |
e9a25f70 | 1526 | |
2a2ab3f9 JVA |
1527 | if (frame_pointer_needed) |
1528 | { | |
e075ae69 RH |
1529 | insn = emit_insn (gen_push (frame_pointer_rtx)); |
1530 | RTX_FRAME_RELATED_P (insn) = 1; | |
e9a25f70 | 1531 | |
e075ae69 RH |
1532 | insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); |
1533 | RTX_FRAME_RELATED_P (insn) = 1; | |
2a2ab3f9 JVA |
1534 | } |
1535 | ||
8dfe5673 RK |
1536 | if (tsize == 0) |
1537 | ; | |
1538 | else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT) | |
469ac993 | 1539 | { |
e075ae69 RH |
1540 | if (frame_pointer_needed) |
1541 | insn = emit_insn (gen_prologue_allocate_stack (stack_pointer_rtx, | |
1542 | stack_pointer_rtx, | |
1543 | GEN_INT (-tsize), | |
1544 | frame_pointer_rtx)); | |
79325812 | 1545 | else |
e075ae69 RH |
1546 | insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, |
1547 | GEN_INT (-tsize))); | |
1548 | RTX_FRAME_RELATED_P (insn) = 1; | |
469ac993 | 1549 | } |
79325812 | 1550 | else |
8dfe5673 | 1551 | { |
e075ae69 | 1552 | /* ??? Is this only valid for Win32? */ |
e9a25f70 | 1553 | |
e075ae69 | 1554 | rtx arg0, sym; |
e9a25f70 | 1555 | |
e075ae69 RH |
1556 | arg0 = gen_rtx_REG (SImode, 0); |
1557 | emit_move_insn (arg0, GEN_INT (tsize)); | |
77a989d1 | 1558 | |
e075ae69 RH |
1559 | sym = gen_rtx_MEM (FUNCTION_MODE, |
1560 | gen_rtx_SYMBOL_REF (Pmode, "_alloca")); | |
1561 | insn = emit_call_insn (gen_call (sym, const0_rtx)); | |
1562 | ||
1563 | CALL_INSN_FUNCTION_USAGE (insn) | |
1564 | = gen_rtx_EXPR_LIST (VOIDmode, arg0, CALL_INSN_FUNCTION_USAGE (insn)); | |
1565 | } | |
e9a25f70 | 1566 | |
2a2ab3f9 JVA |
1567 | limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); |
1568 | for (regno = limit - 1; regno >= 0; regno--) | |
1569 | if ((regs_ever_live[regno] && ! call_used_regs[regno]) | |
aae75261 | 1570 | || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) |
2a2ab3f9 | 1571 | { |
e075ae69 RH |
1572 | insn = emit_insn (gen_push (gen_rtx_REG (SImode, regno))); |
1573 | RTX_FRAME_RELATED_P (insn) = 1; | |
e9a25f70 | 1574 | } |
2a2ab3f9 | 1575 | |
84530511 SC |
1576 | #ifdef SUBTARGET_PROLOGUE |
1577 | SUBTARGET_PROLOGUE; | |
1578 | #endif | |
1579 | ||
e9a25f70 | 1580 | if (pic_reg_used) |
e075ae69 | 1581 | load_pic_register (); |
77a989d1 | 1582 | |
e9a25f70 JL |
1583 | /* If we are profiling, make sure no instructions are scheduled before |
1584 | the call to mcount. However, if -fpic, the above call will have | |
1585 | done that. */ | |
e075ae69 | 1586 | if ((profile_flag || profile_block_flag) && ! pic_reg_used) |
e9a25f70 | 1587 | emit_insn (gen_blockage ()); |
77a989d1 SC |
1588 | } |
1589 | ||
79325812 | 1590 | /* Restore function stack, frame, and registers. */ |
e9a25f70 | 1591 | |
2a2ab3f9 | 1592 | void |
77a989d1 | 1593 | ix86_expand_epilogue () |
2a2ab3f9 JVA |
1594 | { |
1595 | register int regno; | |
65954bd8 JL |
1596 | register int limit; |
1597 | int nregs; | |
aae75261 JVA |
1598 | int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table |
1599 | || current_function_uses_const_pool); | |
fdb8a883 | 1600 | int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging; |
65954bd8 JL |
1601 | HOST_WIDE_INT offset; |
1602 | HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs); | |
2a2ab3f9 | 1603 | |
e075ae69 | 1604 | /* SP is often unreliable so we may have to go off the frame pointer. */ |
2a2ab3f9 | 1605 | |
65954bd8 | 1606 | offset = -(tsize + nregs * UNITS_PER_WORD); |
2a2ab3f9 | 1607 | |
fdb8a883 JW |
1608 | /* If we're only restoring one register and sp is not valid then |
1609 | using a move instruction to restore the register since it's | |
1610 | less work than reloading sp and popping the register. Otherwise, | |
1611 | restore sp (if necessary) and pop the registers. */ | |
1612 | ||
e075ae69 RH |
1613 | limit = (frame_pointer_needed |
1614 | ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); | |
65954bd8 | 1615 | |
fdb8a883 | 1616 | if (nregs > 1 || sp_valid) |
2a2ab3f9 | 1617 | { |
fdb8a883 | 1618 | if ( !sp_valid ) |
2a2ab3f9 | 1619 | { |
e075ae69 RH |
1620 | rtx addr_offset; |
1621 | addr_offset = adj_offsettable_operand (AT_BP (QImode), offset); | |
1622 | addr_offset = XEXP (addr_offset, 0); | |
1623 | ||
1624 | emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, addr_offset)); | |
2a2ab3f9 JVA |
1625 | } |
1626 | ||
1627 | for (regno = 0; regno < limit; regno++) | |
1628 | if ((regs_ever_live[regno] && ! call_used_regs[regno]) | |
aae75261 | 1629 | || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) |
2a2ab3f9 | 1630 | { |
e075ae69 | 1631 | emit_insn (gen_popsi1 (gen_rtx_REG (SImode, regno))); |
2a2ab3f9 JVA |
1632 | } |
1633 | } | |
1634 | else | |
e075ae69 RH |
1635 | { |
1636 | for (regno = 0; regno < limit; regno++) | |
1637 | if ((regs_ever_live[regno] && ! call_used_regs[regno]) | |
1638 | || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) | |
1639 | { | |
1640 | emit_move_insn (gen_rtx_REG (SImode, regno), | |
1641 | adj_offsettable_operand (AT_BP (Pmode), offset)); | |
1642 | offset += 4; | |
1643 | } | |
1644 | } | |
2a2ab3f9 JVA |
1645 | |
1646 | if (frame_pointer_needed) | |
1647 | { | |
c8c5cb99 | 1648 | /* If not an i386, mov & pop is faster than "leave". */ |
3f803cd9 | 1649 | if (TARGET_USE_LEAVE) |
e075ae69 | 1650 | emit_insn (gen_leave()); |
c8c5cb99 | 1651 | else |
2a2ab3f9 | 1652 | { |
e075ae69 RH |
1653 | emit_insn (gen_epilogue_deallocate_stack (stack_pointer_rtx, |
1654 | frame_pointer_rtx)); | |
1655 | emit_insn (gen_popsi1 (frame_pointer_rtx)); | |
e9a25f70 JL |
1656 | } |
1657 | } | |
77a989d1 | 1658 | else if (tsize) |
2a2ab3f9 | 1659 | { |
3403c6ca UD |
1660 | /* Intel's docs say that for 4 or 8 bytes of stack frame one should |
1661 | use `pop' and not `add'. */ | |
1662 | int use_pop = tsize == 4; | |
e075ae69 | 1663 | rtx edx = 0, ecx; |
e9a25f70 | 1664 | |
3403c6ca UD |
1665 | /* Use two pops only for the Pentium processors. */ |
1666 | if (tsize == 8 && !TARGET_386 && !TARGET_486) | |
1667 | { | |
1668 | rtx retval = current_function_return_rtx; | |
1669 | ||
e075ae69 | 1670 | edx = gen_rtx_REG (SImode, 1); |
3403c6ca UD |
1671 | |
1672 | /* This case is a bit more complex. Since we cannot pop into | |
1673 | %ecx twice we need a second register. But this is only | |
1674 | available if the return value is not of DImode in which | |
1675 | case the %edx register is not available. */ | |
1676 | use_pop = (retval == NULL | |
e075ae69 | 1677 | || ! reg_overlap_mentioned_p (edx, retval)); |
3403c6ca UD |
1678 | } |
1679 | ||
1680 | if (use_pop) | |
1681 | { | |
e075ae69 RH |
1682 | ecx = gen_rtx_REG (SImode, 2); |
1683 | ||
1684 | /* We have to prevent the two pops here from being scheduled. | |
1685 | GCC otherwise would try in some situation to put other | |
1686 | instructions in between them which has a bad effect. */ | |
1687 | emit_insn (gen_blockage ()); | |
1688 | emit_insn (gen_popsi1 (ecx)); | |
1689 | if (tsize == 8) | |
1690 | emit_insn (gen_popsi1 (edx)); | |
3403c6ca | 1691 | } |
e9a25f70 | 1692 | else |
3403c6ca UD |
1693 | { |
1694 | /* If there is no frame pointer, we must still release the frame. */ | |
e075ae69 RH |
1695 | emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, |
1696 | GEN_INT (tsize))); | |
3403c6ca | 1697 | } |
2a2ab3f9 JVA |
1698 | } |
1699 | ||
68f654ec RK |
1700 | #ifdef FUNCTION_BLOCK_PROFILER_EXIT |
1701 | if (profile_block_flag == 2) | |
1702 | { | |
e075ae69 | 1703 | FUNCTION_BLOCK_PROFILER_EXIT; |
68f654ec RK |
1704 | } |
1705 | #endif | |
1706 | ||
2a2ab3f9 JVA |
1707 | if (current_function_pops_args && current_function_args_size) |
1708 | { | |
e075ae69 | 1709 | rtx popc = GEN_INT (current_function_pops_args); |
2a2ab3f9 JVA |
1710 | |
1711 | /* i386 can only pop 32K bytes (maybe 64K? Is it signed?). If | |
1712 | asked to pop more, pop return address, do explicit add, and jump | |
1713 | indirectly to the caller. */ | |
1714 | ||
1715 | if (current_function_pops_args >= 32768) | |
1716 | { | |
e075ae69 | 1717 | rtx ecx = gen_rtx_REG (SImode, 2); |
e9a25f70 | 1718 | |
e075ae69 RH |
1719 | emit_insn (gen_popsi1 (ecx)); |
1720 | emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, popc)); | |
1721 | emit_indirect_jump (ecx); | |
e9a25f70 | 1722 | } |
79325812 | 1723 | else |
e075ae69 RH |
1724 | emit_jump_insn (gen_return_pop_internal (popc)); |
1725 | } | |
1726 | else | |
1727 | emit_jump_insn (gen_return_internal ()); | |
1728 | } | |
1729 | \f | |
1730 | /* Extract the parts of an RTL expression that is a valid memory address | |
1731 | for an instruction. Return false if the structure of the address is | |
1732 | grossly off. */ | |
1733 | ||
1734 | static int | |
1735 | ix86_decompose_address (addr, out) | |
1736 | register rtx addr; | |
1737 | struct ix86_address *out; | |
1738 | { | |
1739 | rtx base = NULL_RTX; | |
1740 | rtx index = NULL_RTX; | |
1741 | rtx disp = NULL_RTX; | |
1742 | HOST_WIDE_INT scale = 1; | |
1743 | rtx scale_rtx = NULL_RTX; | |
1744 | ||
1745 | if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG) | |
1746 | base = addr; | |
1747 | else if (GET_CODE (addr) == PLUS) | |
1748 | { | |
1749 | rtx op0 = XEXP (addr, 0); | |
1750 | rtx op1 = XEXP (addr, 1); | |
1751 | enum rtx_code code0 = GET_CODE (op0); | |
1752 | enum rtx_code code1 = GET_CODE (op1); | |
1753 | ||
1754 | if (code0 == REG || code0 == SUBREG) | |
1755 | { | |
1756 | if (code1 == REG || code1 == SUBREG) | |
1757 | index = op0, base = op1; /* index + base */ | |
1758 | else | |
1759 | base = op0, disp = op1; /* base + displacement */ | |
1760 | } | |
1761 | else if (code0 == MULT) | |
e9a25f70 | 1762 | { |
e075ae69 RH |
1763 | index = XEXP (op0, 0); |
1764 | scale_rtx = XEXP (op0, 1); | |
1765 | if (code1 == REG || code1 == SUBREG) | |
1766 | base = op1; /* index*scale + base */ | |
e9a25f70 | 1767 | else |
e075ae69 RH |
1768 | disp = op1; /* index*scale + disp */ |
1769 | } | |
1770 | else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT) | |
1771 | { | |
1772 | index = XEXP (XEXP (op0, 0), 0); /* index*scale + base + disp */ | |
1773 | scale_rtx = XEXP (XEXP (op0, 0), 1); | |
1774 | base = XEXP (op0, 1); | |
1775 | disp = op1; | |
2a2ab3f9 | 1776 | } |
e075ae69 RH |
1777 | else if (code0 == PLUS) |
1778 | { | |
1779 | index = XEXP (op0, 0); /* index + base + disp */ | |
1780 | base = XEXP (op0, 1); | |
1781 | disp = op1; | |
1782 | } | |
1783 | else | |
1784 | return FALSE; | |
1785 | } | |
1786 | else if (GET_CODE (addr) == MULT) | |
1787 | { | |
1788 | index = XEXP (addr, 0); /* index*scale */ | |
1789 | scale_rtx = XEXP (addr, 1); | |
1790 | } | |
1791 | else if (GET_CODE (addr) == ASHIFT) | |
1792 | { | |
1793 | rtx tmp; | |
1794 | ||
1795 | /* We're called for lea too, which implements ashift on occasion. */ | |
1796 | index = XEXP (addr, 0); | |
1797 | tmp = XEXP (addr, 1); | |
1798 | if (GET_CODE (tmp) != CONST_INT) | |
1799 | return FALSE; | |
1800 | scale = INTVAL (tmp); | |
1801 | if ((unsigned HOST_WIDE_INT) scale > 3) | |
1802 | return FALSE; | |
1803 | scale = 1 << scale; | |
2a2ab3f9 | 1804 | } |
2a2ab3f9 | 1805 | else |
e075ae69 RH |
1806 | disp = addr; /* displacement */ |
1807 | ||
1808 | /* Extract the integral value of scale. */ | |
1809 | if (scale_rtx) | |
e9a25f70 | 1810 | { |
e075ae69 RH |
1811 | if (GET_CODE (scale_rtx) != CONST_INT) |
1812 | return FALSE; | |
1813 | scale = INTVAL (scale_rtx); | |
e9a25f70 | 1814 | } |
3b3c6a3f | 1815 | |
e075ae69 RH |
1816 | /* Allow arg pointer and stack pointer as index if there is not scaling */ |
1817 | if (base && index && scale == 1 | |
1818 | && (index == arg_pointer_rtx || index == stack_pointer_rtx)) | |
1819 | { | |
1820 | rtx tmp = base; | |
1821 | base = index; | |
1822 | index = tmp; | |
1823 | } | |
1824 | ||
1825 | /* Special case: %ebp cannot be encoded as a base without a displacement. */ | |
1826 | if (base == frame_pointer_rtx && !disp) | |
1827 | disp = const0_rtx; | |
1828 | ||
1829 | /* Special case: on K6, [%esi] makes the instruction vector decoded. | |
1830 | Avoid this by transforming to [%esi+0]. */ | |
1831 | if (ix86_cpu == PROCESSOR_K6 && !optimize_size | |
1832 | && base && !index && !disp | |
1833 | && REGNO_REG_CLASS (REGNO (base)) == SIREG) | |
1834 | disp = const0_rtx; | |
1835 | ||
1836 | /* Special case: encode reg+reg instead of reg*2. */ | |
1837 | if (!base && index && scale && scale == 2) | |
1838 | base = index, scale = 1; | |
1839 | ||
1840 | /* Special case: scaling cannot be encoded without base or displacement. */ | |
1841 | if (!base && !disp && index && scale != 1) | |
1842 | disp = const0_rtx; | |
1843 | ||
1844 | out->base = base; | |
1845 | out->index = index; | |
1846 | out->disp = disp; | |
1847 | out->scale = scale; | |
3b3c6a3f | 1848 | |
e075ae69 RH |
1849 | return TRUE; |
1850 | } | |
3b3c6a3f | 1851 | |
e075ae69 RH |
1852 | /* Determine if a given CONST RTX is a valid memory displacement |
1853 | in PIC mode. */ | |
1854 | ||
59be65f6 | 1855 | int |
91bb873f RH |
1856 | legitimate_pic_address_disp_p (disp) |
1857 | register rtx disp; | |
1858 | { | |
1859 | if (GET_CODE (disp) != CONST) | |
1860 | return 0; | |
1861 | disp = XEXP (disp, 0); | |
1862 | ||
1863 | if (GET_CODE (disp) == PLUS) | |
1864 | { | |
1865 | if (GET_CODE (XEXP (disp, 1)) != CONST_INT) | |
1866 | return 0; | |
1867 | disp = XEXP (disp, 0); | |
1868 | } | |
1869 | ||
1870 | if (GET_CODE (disp) != UNSPEC | |
1871 | || XVECLEN (disp, 0) != 1) | |
1872 | return 0; | |
1873 | ||
1874 | /* Must be @GOT or @GOTOFF. */ | |
1875 | if (XINT (disp, 1) != 6 | |
1876 | && XINT (disp, 1) != 7) | |
1877 | return 0; | |
1878 | ||
1879 | if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF | |
1880 | && GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF) | |
1881 | return 0; | |
1882 | ||
1883 | return 1; | |
1884 | } | |
1885 | ||
e075ae69 RH |
1886 | /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression that is a valid |
1887 | memory address for an instruction. The MODE argument is the machine mode | |
1888 | for the MEM expression that wants to use this address. | |
1889 | ||
1890 | It only recognizes address in canonical form. LEGITIMIZE_ADDRESS should | |
1891 | convert common non-canonical forms to canonical form so that they will | |
1892 | be recognized. */ | |
1893 | ||
3b3c6a3f MM |
1894 | int |
1895 | legitimate_address_p (mode, addr, strict) | |
1896 | enum machine_mode mode; | |
1897 | register rtx addr; | |
1898 | int strict; | |
1899 | { | |
e075ae69 RH |
1900 | struct ix86_address parts; |
1901 | rtx base, index, disp; | |
1902 | HOST_WIDE_INT scale; | |
1903 | const char *reason = NULL; | |
1904 | rtx reason_rtx = NULL_RTX; | |
3b3c6a3f MM |
1905 | |
1906 | if (TARGET_DEBUG_ADDR) | |
1907 | { | |
1908 | fprintf (stderr, | |
e9a25f70 | 1909 | "\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n", |
3b3c6a3f | 1910 | GET_MODE_NAME (mode), strict); |
3b3c6a3f MM |
1911 | debug_rtx (addr); |
1912 | } | |
1913 | ||
e075ae69 | 1914 | if (! ix86_decompose_address (addr, &parts)) |
3b3c6a3f | 1915 | { |
e075ae69 RH |
1916 | reason = "decomposition failed"; |
1917 | goto error; | |
3b3c6a3f MM |
1918 | } |
1919 | ||
e075ae69 RH |
1920 | base = parts.base; |
1921 | index = parts.index; | |
1922 | disp = parts.disp; | |
1923 | scale = parts.scale; | |
91f0226f | 1924 | |
e075ae69 | 1925 | /* Validate base register. |
e9a25f70 JL |
1926 | |
1927 | Don't allow SUBREG's here, it can lead to spill failures when the base | |
3d771dfd MM |
1928 | is one word out of a two word structure, which is represented internally |
1929 | as a DImode int. */ | |
e9a25f70 | 1930 | |
3b3c6a3f MM |
1931 | if (base) |
1932 | { | |
e075ae69 RH |
1933 | reason_rtx = base; |
1934 | ||
3d771dfd | 1935 | if (GET_CODE (base) != REG) |
3b3c6a3f | 1936 | { |
e075ae69 RH |
1937 | reason = "base is not a register"; |
1938 | goto error; | |
3b3c6a3f MM |
1939 | } |
1940 | ||
c954bd01 RH |
1941 | if (GET_MODE (base) != Pmode) |
1942 | { | |
e075ae69 RH |
1943 | reason = "base is not in Pmode"; |
1944 | goto error; | |
c954bd01 RH |
1945 | } |
1946 | ||
e9a25f70 JL |
1947 | if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base)) |
1948 | || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base))) | |
3b3c6a3f | 1949 | { |
e075ae69 RH |
1950 | reason = "base is not valid"; |
1951 | goto error; | |
3b3c6a3f MM |
1952 | } |
1953 | } | |
1954 | ||
e075ae69 | 1955 | /* Validate index register. |
e9a25f70 JL |
1956 | |
1957 | Don't allow SUBREG's here, it can lead to spill failures when the index | |
3d771dfd MM |
1958 | is one word out of a two word structure, which is represented internally |
1959 | as a DImode int. */ | |
e075ae69 RH |
1960 | |
1961 | if (index) | |
3b3c6a3f | 1962 | { |
e075ae69 RH |
1963 | reason_rtx = index; |
1964 | ||
1965 | if (GET_CODE (index) != REG) | |
3b3c6a3f | 1966 | { |
e075ae69 RH |
1967 | reason = "index is not a register"; |
1968 | goto error; | |
3b3c6a3f MM |
1969 | } |
1970 | ||
e075ae69 | 1971 | if (GET_MODE (index) != Pmode) |
c954bd01 | 1972 | { |
e075ae69 RH |
1973 | reason = "index is not in Pmode"; |
1974 | goto error; | |
c954bd01 RH |
1975 | } |
1976 | ||
e075ae69 RH |
1977 | if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (index)) |
1978 | || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (index))) | |
3b3c6a3f | 1979 | { |
e075ae69 RH |
1980 | reason = "index is not valid"; |
1981 | goto error; | |
3b3c6a3f MM |
1982 | } |
1983 | } | |
3b3c6a3f | 1984 | |
e075ae69 RH |
1985 | /* Validate scale factor. */ |
1986 | if (scale != 1) | |
3b3c6a3f | 1987 | { |
e075ae69 RH |
1988 | reason_rtx = GEN_INT (scale); |
1989 | if (!index) | |
3b3c6a3f | 1990 | { |
e075ae69 RH |
1991 | reason = "scale without index"; |
1992 | goto error; | |
3b3c6a3f MM |
1993 | } |
1994 | ||
e075ae69 | 1995 | if (scale != 2 && scale != 4 && scale != 8) |
3b3c6a3f | 1996 | { |
e075ae69 RH |
1997 | reason = "scale is not a valid multiplier"; |
1998 | goto error; | |
3b3c6a3f MM |
1999 | } |
2000 | } | |
2001 | ||
91bb873f | 2002 | /* Validate displacement. */ |
3b3c6a3f MM |
2003 | if (disp) |
2004 | { | |
e075ae69 RH |
2005 | reason_rtx = disp; |
2006 | ||
91bb873f | 2007 | if (!CONSTANT_ADDRESS_P (disp)) |
3b3c6a3f | 2008 | { |
e075ae69 RH |
2009 | reason = "displacement is not constant"; |
2010 | goto error; | |
3b3c6a3f MM |
2011 | } |
2012 | ||
e075ae69 | 2013 | if (GET_CODE (disp) == CONST_DOUBLE) |
3b3c6a3f | 2014 | { |
e075ae69 RH |
2015 | reason = "displacement is a const_double"; |
2016 | goto error; | |
3b3c6a3f MM |
2017 | } |
2018 | ||
91bb873f | 2019 | if (flag_pic && SYMBOLIC_CONST (disp)) |
3b3c6a3f | 2020 | { |
91bb873f RH |
2021 | if (! legitimate_pic_address_disp_p (disp)) |
2022 | { | |
e075ae69 RH |
2023 | reason = "displacement is an invalid pic construct"; |
2024 | goto error; | |
91bb873f RH |
2025 | } |
2026 | ||
e075ae69 RH |
2027 | /* Verify that a symbolic pic displacement includes |
2028 | the pic_offset_table_rtx register. */ | |
91bb873f | 2029 | if (base != pic_offset_table_rtx |
e075ae69 | 2030 | && (index != pic_offset_table_rtx || scale != 1)) |
91bb873f | 2031 | { |
e075ae69 RH |
2032 | reason = "pic displacement against invalid base"; |
2033 | goto error; | |
91bb873f | 2034 | } |
3b3c6a3f | 2035 | } |
91bb873f | 2036 | else if (HALF_PIC_P ()) |
3b3c6a3f | 2037 | { |
91bb873f | 2038 | if (! HALF_PIC_ADDRESS_P (disp) |
e075ae69 | 2039 | || (base != NULL_RTX || index != NULL_RTX)) |
91bb873f | 2040 | { |
e075ae69 RH |
2041 | reason = "displacement is an invalid half-pic reference"; |
2042 | goto error; | |
91bb873f | 2043 | } |
3b3c6a3f MM |
2044 | } |
2045 | } | |
2046 | ||
e075ae69 | 2047 | /* Everything looks valid. */ |
3b3c6a3f | 2048 | if (TARGET_DEBUG_ADDR) |
e075ae69 | 2049 | fprintf (stderr, "Success.\n"); |
3b3c6a3f | 2050 | return TRUE; |
e075ae69 RH |
2051 | |
2052 | error: | |
2053 | if (TARGET_DEBUG_ADDR) | |
2054 | { | |
2055 | fprintf (stderr, "Error: %s\n", reason); | |
2056 | debug_rtx (reason_rtx); | |
2057 | } | |
2058 | return FALSE; | |
3b3c6a3f | 2059 | } |
3b3c6a3f MM |
2060 | \f |
2061 | /* Return a legitimate reference for ORIG (an address) using the | |
2062 | register REG. If REG is 0, a new pseudo is generated. | |
2063 | ||
91bb873f | 2064 | There are two types of references that must be handled: |
3b3c6a3f MM |
2065 | |
2066 | 1. Global data references must load the address from the GOT, via | |
2067 | the PIC reg. An insn is emitted to do this load, and the reg is | |
2068 | returned. | |
2069 | ||
91bb873f RH |
2070 | 2. Static data references, constant pool addresses, and code labels |
2071 | compute the address as an offset from the GOT, whose base is in | |
2072 | the PIC reg. Static data objects have SYMBOL_REF_FLAG set to | |
2073 | differentiate them from global data objects. The returned | |
2074 | address is the PIC reg + an unspec constant. | |
3b3c6a3f MM |
2075 | |
2076 | GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC | |
91bb873f | 2077 | reg also appears in the address. */ |
3b3c6a3f MM |
2078 | |
2079 | rtx | |
2080 | legitimize_pic_address (orig, reg) | |
2081 | rtx orig; | |
2082 | rtx reg; | |
2083 | { | |
2084 | rtx addr = orig; | |
2085 | rtx new = orig; | |
91bb873f | 2086 | rtx base; |
3b3c6a3f | 2087 | |
91bb873f RH |
2088 | if (GET_CODE (addr) == LABEL_REF |
2089 | || (GET_CODE (addr) == SYMBOL_REF | |
2090 | && (CONSTANT_POOL_ADDRESS_P (addr) | |
2091 | || SYMBOL_REF_FLAG (addr)))) | |
3b3c6a3f | 2092 | { |
91bb873f RH |
2093 | /* This symbol may be referenced via a displacement from the PIC |
2094 | base address (@GOTOFF). */ | |
3b3c6a3f | 2095 | |
91bb873f RH |
2096 | current_function_uses_pic_offset_table = 1; |
2097 | new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), 7); | |
2098 | new = gen_rtx_CONST (VOIDmode, new); | |
2099 | new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); | |
3b3c6a3f | 2100 | |
91bb873f RH |
2101 | if (reg != 0) |
2102 | { | |
3b3c6a3f | 2103 | emit_move_insn (reg, new); |
91bb873f | 2104 | new = reg; |
3b3c6a3f | 2105 | } |
3b3c6a3f | 2106 | } |
91bb873f | 2107 | else if (GET_CODE (addr) == SYMBOL_REF) |
3b3c6a3f | 2108 | { |
91bb873f RH |
2109 | /* This symbol must be referenced via a load from the |
2110 | Global Offset Table (@GOT). */ | |
3b3c6a3f | 2111 | |
91bb873f RH |
2112 | current_function_uses_pic_offset_table = 1; |
2113 | new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), 6); | |
2114 | new = gen_rtx_CONST (VOIDmode, new); | |
2115 | new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); | |
2116 | new = gen_rtx_MEM (Pmode, new); | |
2117 | RTX_UNCHANGING_P (new) = 1; | |
3b3c6a3f MM |
2118 | |
2119 | if (reg == 0) | |
2120 | reg = gen_reg_rtx (Pmode); | |
91bb873f RH |
2121 | emit_move_insn (reg, new); |
2122 | new = reg; | |
2123 | } | |
2124 | else | |
2125 | { | |
2126 | if (GET_CODE (addr) == CONST) | |
3b3c6a3f | 2127 | { |
91bb873f RH |
2128 | addr = XEXP (addr, 0); |
2129 | if (GET_CODE (addr) == UNSPEC) | |
2130 | { | |
2131 | /* Check that the unspec is one of the ones we generate? */ | |
2132 | } | |
2133 | else if (GET_CODE (addr) != PLUS) | |
2134 | abort(); | |
3b3c6a3f | 2135 | } |
91bb873f RH |
2136 | if (GET_CODE (addr) == PLUS) |
2137 | { | |
2138 | rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1); | |
e9a25f70 | 2139 | |
91bb873f RH |
2140 | /* Check first to see if this is a constant offset from a @GOTOFF |
2141 | symbol reference. */ | |
2142 | if ((GET_CODE (op0) == LABEL_REF | |
2143 | || (GET_CODE (op0) == SYMBOL_REF | |
2144 | && (CONSTANT_POOL_ADDRESS_P (op0) | |
2145 | || SYMBOL_REF_FLAG (op0)))) | |
2146 | && GET_CODE (op1) == CONST_INT) | |
2147 | { | |
2148 | current_function_uses_pic_offset_table = 1; | |
2149 | new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, op0), 7); | |
2150 | new = gen_rtx_PLUS (VOIDmode, new, op1); | |
2151 | new = gen_rtx_CONST (VOIDmode, new); | |
2152 | new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); | |
2153 | ||
2154 | if (reg != 0) | |
2155 | { | |
2156 | emit_move_insn (reg, new); | |
2157 | new = reg; | |
2158 | } | |
2159 | } | |
2160 | else | |
2161 | { | |
2162 | base = legitimize_pic_address (XEXP (addr, 0), reg); | |
2163 | new = legitimize_pic_address (XEXP (addr, 1), | |
2164 | base == reg ? NULL_RTX : reg); | |
2165 | ||
2166 | if (GET_CODE (new) == CONST_INT) | |
2167 | new = plus_constant (base, INTVAL (new)); | |
2168 | else | |
2169 | { | |
2170 | if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1))) | |
2171 | { | |
2172 | base = gen_rtx_PLUS (Pmode, base, XEXP (new, 0)); | |
2173 | new = XEXP (new, 1); | |
2174 | } | |
2175 | new = gen_rtx_PLUS (Pmode, base, new); | |
2176 | } | |
2177 | } | |
2178 | } | |
3b3c6a3f MM |
2179 | } |
2180 | return new; | |
2181 | } | |
2182 | \f | |
3b3c6a3f MM |
2183 | /* Try machine-dependent ways of modifying an illegitimate address |
2184 | to be legitimate. If we find one, return the new, valid address. | |
2185 | This macro is used in only one place: `memory_address' in explow.c. | |
2186 | ||
2187 | OLDX is the address as it was before break_out_memory_refs was called. | |
2188 | In some cases it is useful to look at this to decide what needs to be done. | |
2189 | ||
2190 | MODE and WIN are passed so that this macro can use | |
2191 | GO_IF_LEGITIMATE_ADDRESS. | |
2192 | ||
2193 | It is always safe for this macro to do nothing. It exists to recognize | |
2194 | opportunities to optimize the output. | |
2195 | ||
2196 | For the 80386, we handle X+REG by loading X into a register R and | |
2197 | using R+REG. R will go in a general reg and indexing will be used. | |
2198 | However, if REG is a broken-out memory address or multiplication, | |
2199 | nothing needs to be done because REG can certainly go in a general reg. | |
2200 | ||
2201 | When -fpic is used, special handling is needed for symbolic references. | |
2202 | See comments by legitimize_pic_address in i386.c for details. */ | |
2203 | ||
2204 | rtx | |
2205 | legitimize_address (x, oldx, mode) | |
2206 | register rtx x; | |
bb5177ac | 2207 | register rtx oldx ATTRIBUTE_UNUSED; |
3b3c6a3f MM |
2208 | enum machine_mode mode; |
2209 | { | |
2210 | int changed = 0; | |
2211 | unsigned log; | |
2212 | ||
2213 | if (TARGET_DEBUG_ADDR) | |
2214 | { | |
e9a25f70 JL |
2215 | fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n", |
2216 | GET_MODE_NAME (mode)); | |
3b3c6a3f MM |
2217 | debug_rtx (x); |
2218 | } | |
2219 | ||
2220 | if (flag_pic && SYMBOLIC_CONST (x)) | |
2221 | return legitimize_pic_address (x, 0); | |
2222 | ||
2223 | /* Canonicalize shifts by 0, 1, 2, 3 into multiply */ | |
2224 | if (GET_CODE (x) == ASHIFT | |
2225 | && GET_CODE (XEXP (x, 1)) == CONST_INT | |
2226 | && (log = (unsigned)exact_log2 (INTVAL (XEXP (x, 1)))) < 4) | |
2227 | { | |
2228 | changed = 1; | |
a269a03c JC |
2229 | x = gen_rtx_MULT (Pmode, force_reg (Pmode, XEXP (x, 0)), |
2230 | GEN_INT (1 << log)); | |
3b3c6a3f MM |
2231 | } |
2232 | ||
2233 | if (GET_CODE (x) == PLUS) | |
2234 | { | |
e9a25f70 JL |
2235 | /* Canonicalize shifts by 0, 1, 2, 3 into multiply. */ |
2236 | ||
3b3c6a3f MM |
2237 | if (GET_CODE (XEXP (x, 0)) == ASHIFT |
2238 | && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT | |
2239 | && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) < 4) | |
2240 | { | |
2241 | changed = 1; | |
c5c76735 JL |
2242 | XEXP (x, 0) = gen_rtx_MULT (Pmode, |
2243 | force_reg (Pmode, XEXP (XEXP (x, 0), 0)), | |
2244 | GEN_INT (1 << log)); | |
3b3c6a3f MM |
2245 | } |
2246 | ||
2247 | if (GET_CODE (XEXP (x, 1)) == ASHIFT | |
2248 | && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT | |
2249 | && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 1), 1)))) < 4) | |
2250 | { | |
2251 | changed = 1; | |
c5c76735 JL |
2252 | XEXP (x, 1) = gen_rtx_MULT (Pmode, |
2253 | force_reg (Pmode, XEXP (XEXP (x, 1), 0)), | |
2254 | GEN_INT (1 << log)); | |
3b3c6a3f MM |
2255 | } |
2256 | ||
e9a25f70 | 2257 | /* Put multiply first if it isn't already. */ |
3b3c6a3f MM |
2258 | if (GET_CODE (XEXP (x, 1)) == MULT) |
2259 | { | |
2260 | rtx tmp = XEXP (x, 0); | |
2261 | XEXP (x, 0) = XEXP (x, 1); | |
2262 | XEXP (x, 1) = tmp; | |
2263 | changed = 1; | |
2264 | } | |
2265 | ||
2266 | /* Canonicalize (plus (mult (reg) (const)) (plus (reg) (const))) | |
2267 | into (plus (plus (mult (reg) (const)) (reg)) (const)). This can be | |
2268 | created by virtual register instantiation, register elimination, and | |
2269 | similar optimizations. */ | |
2270 | if (GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == PLUS) | |
2271 | { | |
2272 | changed = 1; | |
c5c76735 JL |
2273 | x = gen_rtx_PLUS (Pmode, |
2274 | gen_rtx_PLUS (Pmode, XEXP (x, 0), | |
2275 | XEXP (XEXP (x, 1), 0)), | |
2276 | XEXP (XEXP (x, 1), 1)); | |
3b3c6a3f MM |
2277 | } |
2278 | ||
e9a25f70 JL |
2279 | /* Canonicalize |
2280 | (plus (plus (mult (reg) (const)) (plus (reg) (const))) const) | |
3b3c6a3f MM |
2281 | into (plus (plus (mult (reg) (const)) (reg)) (const)). */ |
2282 | else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS | |
2283 | && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT | |
2284 | && GET_CODE (XEXP (XEXP (x, 0), 1)) == PLUS | |
2285 | && CONSTANT_P (XEXP (x, 1))) | |
2286 | { | |
00c79232 ML |
2287 | rtx constant; |
2288 | rtx other = NULL_RTX; | |
3b3c6a3f MM |
2289 | |
2290 | if (GET_CODE (XEXP (x, 1)) == CONST_INT) | |
2291 | { | |
2292 | constant = XEXP (x, 1); | |
2293 | other = XEXP (XEXP (XEXP (x, 0), 1), 1); | |
2294 | } | |
2295 | else if (GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 1)) == CONST_INT) | |
2296 | { | |
2297 | constant = XEXP (XEXP (XEXP (x, 0), 1), 1); | |
2298 | other = XEXP (x, 1); | |
2299 | } | |
2300 | else | |
2301 | constant = 0; | |
2302 | ||
2303 | if (constant) | |
2304 | { | |
2305 | changed = 1; | |
c5c76735 JL |
2306 | x = gen_rtx_PLUS (Pmode, |
2307 | gen_rtx_PLUS (Pmode, XEXP (XEXP (x, 0), 0), | |
2308 | XEXP (XEXP (XEXP (x, 0), 1), 0)), | |
2309 | plus_constant (other, INTVAL (constant))); | |
3b3c6a3f MM |
2310 | } |
2311 | } | |
2312 | ||
2313 | if (changed && legitimate_address_p (mode, x, FALSE)) | |
2314 | return x; | |
2315 | ||
2316 | if (GET_CODE (XEXP (x, 0)) == MULT) | |
2317 | { | |
2318 | changed = 1; | |
2319 | XEXP (x, 0) = force_operand (XEXP (x, 0), 0); | |
2320 | } | |
2321 | ||
2322 | if (GET_CODE (XEXP (x, 1)) == MULT) | |
2323 | { | |
2324 | changed = 1; | |
2325 | XEXP (x, 1) = force_operand (XEXP (x, 1), 0); | |
2326 | } | |
2327 | ||
2328 | if (changed | |
2329 | && GET_CODE (XEXP (x, 1)) == REG | |
2330 | && GET_CODE (XEXP (x, 0)) == REG) | |
2331 | return x; | |
2332 | ||
2333 | if (flag_pic && SYMBOLIC_CONST (XEXP (x, 1))) | |
2334 | { | |
2335 | changed = 1; | |
2336 | x = legitimize_pic_address (x, 0); | |
2337 | } | |
2338 | ||
2339 | if (changed && legitimate_address_p (mode, x, FALSE)) | |
2340 | return x; | |
2341 | ||
2342 | if (GET_CODE (XEXP (x, 0)) == REG) | |
2343 | { | |
2344 | register rtx temp = gen_reg_rtx (Pmode); | |
2345 | register rtx val = force_operand (XEXP (x, 1), temp); | |
2346 | if (val != temp) | |
2347 | emit_move_insn (temp, val); | |
2348 | ||
2349 | XEXP (x, 1) = temp; | |
2350 | return x; | |
2351 | } | |
2352 | ||
2353 | else if (GET_CODE (XEXP (x, 1)) == REG) | |
2354 | { | |
2355 | register rtx temp = gen_reg_rtx (Pmode); | |
2356 | register rtx val = force_operand (XEXP (x, 0), temp); | |
2357 | if (val != temp) | |
2358 | emit_move_insn (temp, val); | |
2359 | ||
2360 | XEXP (x, 0) = temp; | |
2361 | return x; | |
2362 | } | |
2363 | } | |
2364 | ||
2365 | return x; | |
2366 | } | |
2a2ab3f9 JVA |
2367 | \f |
2368 | /* Print an integer constant expression in assembler syntax. Addition | |
2369 | and subtraction are the only arithmetic that may appear in these | |
2370 | expressions. FILE is the stdio stream to write to, X is the rtx, and | |
2371 | CODE is the operand print code from the output string. */ | |
2372 | ||
2373 | static void | |
2374 | output_pic_addr_const (file, x, code) | |
2375 | FILE *file; | |
2376 | rtx x; | |
2377 | int code; | |
2378 | { | |
2379 | char buf[256]; | |
2380 | ||
2381 | switch (GET_CODE (x)) | |
2382 | { | |
2383 | case PC: | |
2384 | if (flag_pic) | |
2385 | putc ('.', file); | |
2386 | else | |
2387 | abort (); | |
2388 | break; | |
2389 | ||
2390 | case SYMBOL_REF: | |
91bb873f RH |
2391 | assemble_name (file, XSTR (x, 0)); |
2392 | if (code == 'P' && ! SYMBOL_REF_FLAG (x)) | |
2393 | fputs ("@PLT", file); | |
2a2ab3f9 JVA |
2394 | break; |
2395 | ||
91bb873f RH |
2396 | case LABEL_REF: |
2397 | x = XEXP (x, 0); | |
2398 | /* FALLTHRU */ | |
2a2ab3f9 JVA |
2399 | case CODE_LABEL: |
2400 | ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); | |
2401 | assemble_name (asm_out_file, buf); | |
2402 | break; | |
2403 | ||
2404 | case CONST_INT: | |
f64cecad | 2405 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); |
2a2ab3f9 JVA |
2406 | break; |
2407 | ||
2408 | case CONST: | |
2409 | /* This used to output parentheses around the expression, | |
2410 | but that does not work on the 386 (either ATT or BSD assembler). */ | |
2411 | output_pic_addr_const (file, XEXP (x, 0), code); | |
2412 | break; | |
2413 | ||
2414 | case CONST_DOUBLE: | |
2415 | if (GET_MODE (x) == VOIDmode) | |
2416 | { | |
2417 | /* We can use %d if the number is <32 bits and positive. */ | |
2418 | if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0) | |
f64cecad JC |
2419 | fprintf (file, "0x%lx%08lx", |
2420 | (unsigned long) CONST_DOUBLE_HIGH (x), | |
2421 | (unsigned long) CONST_DOUBLE_LOW (x)); | |
2a2ab3f9 | 2422 | else |
f64cecad | 2423 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x)); |
2a2ab3f9 JVA |
2424 | } |
2425 | else | |
2426 | /* We can't handle floating point constants; | |
2427 | PRINT_OPERAND must handle them. */ | |
2428 | output_operand_lossage ("floating constant misused"); | |
2429 | break; | |
2430 | ||
2431 | case PLUS: | |
e9a25f70 | 2432 | /* Some assemblers need integer constants to appear first. */ |
2a2ab3f9 JVA |
2433 | if (GET_CODE (XEXP (x, 0)) == CONST_INT) |
2434 | { | |
2a2ab3f9 | 2435 | output_pic_addr_const (file, XEXP (x, 0), code); |
e075ae69 | 2436 | putc ('+', file); |
e9a25f70 | 2437 | output_pic_addr_const (file, XEXP (x, 1), code); |
2a2ab3f9 | 2438 | } |
91bb873f | 2439 | else if (GET_CODE (XEXP (x, 1)) == CONST_INT) |
2a2ab3f9 | 2440 | { |
2a2ab3f9 | 2441 | output_pic_addr_const (file, XEXP (x, 1), code); |
e075ae69 | 2442 | putc ('+', file); |
e9a25f70 | 2443 | output_pic_addr_const (file, XEXP (x, 0), code); |
2a2ab3f9 | 2444 | } |
91bb873f RH |
2445 | else |
2446 | abort (); | |
2a2ab3f9 JVA |
2447 | break; |
2448 | ||
2449 | case MINUS: | |
e075ae69 | 2450 | putc (ASSEMBLER_DIALECT ? '(' : '[', file); |
2a2ab3f9 | 2451 | output_pic_addr_const (file, XEXP (x, 0), code); |
e075ae69 | 2452 | putc ('-', file); |
2a2ab3f9 | 2453 | output_pic_addr_const (file, XEXP (x, 1), code); |
e075ae69 | 2454 | putc (ASSEMBLER_DIALECT ? ')' : ']', file); |
2a2ab3f9 JVA |
2455 | break; |
2456 | ||
91bb873f RH |
2457 | case UNSPEC: |
2458 | if (XVECLEN (x, 0) != 1) | |
2459 | abort (); | |
2460 | output_pic_addr_const (file, XVECEXP (x, 0, 0), code); | |
2461 | switch (XINT (x, 1)) | |
2462 | { | |
2463 | case 6: | |
2464 | fputs ("@GOT", file); | |
2465 | break; | |
2466 | case 7: | |
2467 | fputs ("@GOTOFF", file); | |
2468 | break; | |
2469 | case 8: | |
2470 | fputs ("@PLT", file); | |
2471 | break; | |
2472 | default: | |
2473 | output_operand_lossage ("invalid UNSPEC as operand"); | |
2474 | break; | |
2475 | } | |
2476 | break; | |
2477 | ||
2a2ab3f9 JVA |
2478 | default: |
2479 | output_operand_lossage ("invalid expression as operand"); | |
2480 | } | |
2481 | } | |
2482 | \f | |
a269a03c | 2483 | static void |
e075ae69 | 2484 | put_condition_code (code, mode, reverse, fp, file) |
a269a03c | 2485 | enum rtx_code code; |
e075ae69 RH |
2486 | enum machine_mode mode; |
2487 | int reverse, fp; | |
a269a03c JC |
2488 | FILE *file; |
2489 | { | |
a269a03c JC |
2490 | const char *suffix; |
2491 | ||
a269a03c JC |
2492 | if (reverse) |
2493 | code = reverse_condition (code); | |
e075ae69 | 2494 | |
a269a03c JC |
2495 | switch (code) |
2496 | { | |
2497 | case EQ: | |
2498 | suffix = "e"; | |
2499 | break; | |
a269a03c JC |
2500 | case NE: |
2501 | suffix = "ne"; | |
2502 | break; | |
a269a03c | 2503 | case GT: |
e075ae69 RH |
2504 | if (mode == CCNOmode) |
2505 | abort (); | |
2506 | suffix = "g"; | |
a269a03c | 2507 | break; |
a269a03c | 2508 | case GTU: |
e075ae69 RH |
2509 | /* ??? Use "nbe" instead of "a" for fcmov losage on some assemblers. |
2510 | Those same assemblers have the same but opposite losage on cmov. */ | |
2511 | suffix = fp ? "nbe" : "a"; | |
a269a03c | 2512 | break; |
a269a03c | 2513 | case LT: |
e075ae69 | 2514 | if (mode == CCNOmode) |
a269a03c JC |
2515 | suffix = "s"; |
2516 | else | |
e075ae69 | 2517 | suffix = "l"; |
a269a03c | 2518 | break; |
a269a03c JC |
2519 | case LTU: |
2520 | suffix = "b"; | |
2521 | break; | |
a269a03c | 2522 | case GE: |
e075ae69 | 2523 | if (mode == CCNOmode) |
a269a03c JC |
2524 | suffix = "ns"; |
2525 | else | |
e075ae69 | 2526 | suffix = "ge"; |
a269a03c | 2527 | break; |
a269a03c | 2528 | case GEU: |
e075ae69 RH |
2529 | /* ??? As above. */ |
2530 | suffix = fp ? "nb" : "ae"; | |
a269a03c | 2531 | break; |
a269a03c | 2532 | case LE: |
e075ae69 RH |
2533 | if (mode == CCNOmode) |
2534 | abort (); | |
2535 | suffix = "le"; | |
a269a03c | 2536 | break; |
a269a03c JC |
2537 | case LEU: |
2538 | suffix = "be"; | |
2539 | break; | |
a269a03c JC |
2540 | default: |
2541 | abort (); | |
2542 | } | |
2543 | fputs (suffix, file); | |
2544 | } | |
2545 | ||
e075ae69 RH |
2546 | void |
2547 | print_reg (x, code, file) | |
2548 | rtx x; | |
2549 | int code; | |
2550 | FILE *file; | |
e5cb57e8 | 2551 | { |
e075ae69 RH |
2552 | if (REGNO (x) == ARG_POINTER_REGNUM |
2553 | || REGNO (x) == FLAGS_REG | |
2554 | || REGNO (x) == FPSR_REG) | |
2555 | abort (); | |
e9a25f70 | 2556 | |
e075ae69 RH |
2557 | if (ASSEMBLER_DIALECT == 0 || USER_LABEL_PREFIX[0] == 0) |
2558 | putc ('%', file); | |
2559 | ||
2560 | if (code == 'w') | |
2561 | code = 2; | |
2562 | else if (code == 'b') | |
2563 | code = 1; | |
2564 | else if (code == 'k') | |
2565 | code = 4; | |
2566 | else if (code == 'y') | |
2567 | code = 3; | |
2568 | else if (code == 'h') | |
2569 | code = 0; | |
2570 | else | |
2571 | code = GET_MODE_SIZE (GET_MODE (x)); | |
e9a25f70 | 2572 | |
e075ae69 RH |
2573 | switch (code) |
2574 | { | |
2575 | case 3: | |
2576 | if (STACK_TOP_P (x)) | |
2577 | { | |
2578 | fputs ("st(0)", file); | |
2579 | break; | |
2580 | } | |
2581 | /* FALLTHRU */ | |
2582 | case 4: | |
2583 | case 8: | |
2584 | case 12: | |
2585 | if (! FP_REG_P (x)) | |
2586 | putc ('e', file); | |
2587 | /* FALLTHRU */ | |
2588 | case 2: | |
2589 | fputs (hi_reg_name[REGNO (x)], file); | |
2590 | break; | |
2591 | case 1: | |
2592 | fputs (qi_reg_name[REGNO (x)], file); | |
2593 | break; | |
2594 | case 0: | |
2595 | fputs (qi_high_reg_name[REGNO (x)], file); | |
2596 | break; | |
2597 | default: | |
2598 | abort (); | |
fe25fea3 | 2599 | } |
e5cb57e8 SC |
2600 | } |
2601 | ||
2a2ab3f9 | 2602 | /* Meaning of CODE: |
fe25fea3 | 2603 | L,W,B,Q,S,T -- print the opcode suffix for specified size of operand. |
e5cb57e8 | 2604 | C -- print opcode suffix for set/cmov insn. |
fe25fea3 | 2605 | c -- like C, but print reversed condition |
2a2ab3f9 JVA |
2606 | R -- print the prefix for register names. |
2607 | z -- print the opcode suffix for the size of the current operand. | |
2608 | * -- print a star (in certain assembler syntax) | |
2609 | w -- print the operand as if it's a "word" (HImode) even if it isn't. | |
2d49677f SC |
2610 | s -- print a shift double count, followed by the assemblers argument |
2611 | delimiter. | |
fe25fea3 SC |
2612 | b -- print the QImode name of the register for the indicated operand. |
2613 | %b0 would print %al if operands[0] is reg 0. | |
2614 | w -- likewise, print the HImode name of the register. | |
2615 | k -- likewise, print the SImode name of the register. | |
2616 | h -- print the QImode name for a "high" register, either ah, bh, ch or dh. | |
e075ae69 | 2617 | y -- print "st(0)" instead of "st" as a register. */ |
2a2ab3f9 JVA |
2618 | |
2619 | void | |
2620 | print_operand (file, x, code) | |
2621 | FILE *file; | |
2622 | rtx x; | |
2623 | int code; | |
2624 | { | |
2625 | if (code) | |
2626 | { | |
2627 | switch (code) | |
2628 | { | |
2629 | case '*': | |
e075ae69 | 2630 | if (ASSEMBLER_DIALECT == 0) |
2a2ab3f9 JVA |
2631 | putc ('*', file); |
2632 | return; | |
2633 | ||
2a2ab3f9 | 2634 | case 'L': |
e075ae69 RH |
2635 | if (ASSEMBLER_DIALECT == 0) |
2636 | putc ('l', file); | |
2a2ab3f9 JVA |
2637 | return; |
2638 | ||
2639 | case 'W': | |
e075ae69 RH |
2640 | if (ASSEMBLER_DIALECT == 0) |
2641 | putc ('w', file); | |
2a2ab3f9 JVA |
2642 | return; |
2643 | ||
2644 | case 'B': | |
e075ae69 RH |
2645 | if (ASSEMBLER_DIALECT == 0) |
2646 | putc ('b', file); | |
2a2ab3f9 JVA |
2647 | return; |
2648 | ||
2649 | case 'Q': | |
e075ae69 RH |
2650 | if (ASSEMBLER_DIALECT == 0) |
2651 | putc ('l', file); | |
2a2ab3f9 JVA |
2652 | return; |
2653 | ||
2654 | case 'S': | |
e075ae69 RH |
2655 | if (ASSEMBLER_DIALECT == 0) |
2656 | putc ('s', file); | |
2a2ab3f9 JVA |
2657 | return; |
2658 | ||
5f1ec3e6 | 2659 | case 'T': |
e075ae69 RH |
2660 | if (ASSEMBLER_DIALECT == 0) |
2661 | putc ('t', file); | |
5f1ec3e6 JVA |
2662 | return; |
2663 | ||
2a2ab3f9 JVA |
2664 | case 'z': |
2665 | /* 387 opcodes don't get size suffixes if the operands are | |
2666 | registers. */ | |
2667 | ||
2668 | if (STACK_REG_P (x)) | |
2669 | return; | |
2670 | ||
e075ae69 RH |
2671 | /* Intel syntax has no truck with instruction suffixes. */ |
2672 | if (ASSEMBLER_DIALECT != 0) | |
2673 | return; | |
2674 | ||
2a2ab3f9 JVA |
2675 | /* this is the size of op from size of operand */ |
2676 | switch (GET_MODE_SIZE (GET_MODE (x))) | |
2677 | { | |
e075ae69 RH |
2678 | case 1: |
2679 | putc ('b', file); | |
2680 | return; | |
2681 | ||
2a2ab3f9 | 2682 | case 2: |
e075ae69 | 2683 | putc ('w', file); |
2a2ab3f9 JVA |
2684 | return; |
2685 | ||
2686 | case 4: | |
2687 | if (GET_MODE (x) == SFmode) | |
2688 | { | |
e075ae69 | 2689 | putc ('s', file); |
2a2ab3f9 JVA |
2690 | return; |
2691 | } | |
2692 | else | |
e075ae69 | 2693 | putc ('l', file); |
2a2ab3f9 JVA |
2694 | return; |
2695 | ||
5f1ec3e6 | 2696 | case 12: |
e075ae69 RH |
2697 | putc ('t', file); |
2698 | return; | |
5f1ec3e6 | 2699 | |
2a2ab3f9 JVA |
2700 | case 8: |
2701 | if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT) | |
56c0e8fa JVA |
2702 | { |
2703 | #ifdef GAS_MNEMONICS | |
e075ae69 | 2704 | putc ('q', file); |
56c0e8fa | 2705 | #else |
e075ae69 RH |
2706 | putc ('l', file); |
2707 | putc ('l', file); | |
56c0e8fa JVA |
2708 | #endif |
2709 | } | |
e075ae69 RH |
2710 | else |
2711 | putc ('l', file); | |
2a2ab3f9 JVA |
2712 | return; |
2713 | } | |
4af3895e JVA |
2714 | |
2715 | case 'b': | |
2716 | case 'w': | |
2717 | case 'k': | |
2718 | case 'h': | |
2719 | case 'y': | |
5cb6195d | 2720 | case 'X': |
e075ae69 | 2721 | case 'P': |
4af3895e JVA |
2722 | break; |
2723 | ||
2d49677f SC |
2724 | case 's': |
2725 | if (GET_CODE (x) == CONST_INT || ! SHIFT_DOUBLE_OMITS_COUNT) | |
2726 | { | |
2727 | PRINT_OPERAND (file, x, 0); | |
e075ae69 | 2728 | putc (',', file); |
2d49677f | 2729 | } |
a269a03c JC |
2730 | return; |
2731 | ||
1853aadd | 2732 | case 'C': |
e075ae69 | 2733 | put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 0, 0, file); |
1853aadd | 2734 | return; |
fe25fea3 | 2735 | case 'F': |
e075ae69 | 2736 | put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 0, 1, file); |
fe25fea3 SC |
2737 | return; |
2738 | ||
e9a25f70 | 2739 | /* Like above, but reverse condition */ |
e075ae69 RH |
2740 | case 'c': |
2741 | put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 0, file); | |
2742 | return; | |
fe25fea3 | 2743 | case 'f': |
e075ae69 | 2744 | put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 1, file); |
1853aadd | 2745 | return; |
e5cb57e8 | 2746 | |
4af3895e | 2747 | default: |
68daafd4 JVA |
2748 | { |
2749 | char str[50]; | |
68daafd4 JVA |
2750 | sprintf (str, "invalid operand code `%c'", code); |
2751 | output_operand_lossage (str); | |
2752 | } | |
2a2ab3f9 JVA |
2753 | } |
2754 | } | |
e9a25f70 | 2755 | |
2a2ab3f9 JVA |
2756 | if (GET_CODE (x) == REG) |
2757 | { | |
2758 | PRINT_REG (x, code, file); | |
2759 | } | |
e9a25f70 | 2760 | |
2a2ab3f9 JVA |
2761 | else if (GET_CODE (x) == MEM) |
2762 | { | |
e075ae69 RH |
2763 | /* No `byte ptr' prefix for call instructions. */ |
2764 | if (ASSEMBLER_DIALECT != 0 && code != 'X' && code != 'P') | |
2a2ab3f9 | 2765 | { |
e075ae69 RH |
2766 | char * size; |
2767 | switch (GET_MODE_SIZE (GET_MODE (x))) | |
2768 | { | |
2769 | case 1: size = "BYTE"; break; | |
2770 | case 2: size = "WORD"; break; | |
2771 | case 4: size = "DWORD"; break; | |
2772 | case 8: size = "QWORD"; break; | |
2773 | case 12: size = "XWORD"; break; | |
2774 | default: | |
2775 | abort(); | |
2776 | } | |
2777 | fputs (size, file); | |
2778 | fputs (" PTR ", file); | |
2a2ab3f9 | 2779 | } |
e075ae69 RH |
2780 | |
2781 | x = XEXP (x, 0); | |
2782 | if (flag_pic && CONSTANT_ADDRESS_P (x)) | |
2783 | output_pic_addr_const (file, x, code); | |
2a2ab3f9 | 2784 | else |
e075ae69 | 2785 | output_address (x); |
2a2ab3f9 | 2786 | } |
e9a25f70 | 2787 | |
2a2ab3f9 JVA |
2788 | else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode) |
2789 | { | |
e9a25f70 JL |
2790 | REAL_VALUE_TYPE r; |
2791 | long l; | |
2792 | ||
5f1ec3e6 JVA |
2793 | REAL_VALUE_FROM_CONST_DOUBLE (r, x); |
2794 | REAL_VALUE_TO_TARGET_SINGLE (r, l); | |
e075ae69 RH |
2795 | |
2796 | if (ASSEMBLER_DIALECT == 0) | |
2797 | putc ('$', file); | |
52267fcb | 2798 | fprintf (file, "0x%lx", l); |
5f1ec3e6 | 2799 | } |
e9a25f70 | 2800 | |
5f1ec3e6 JVA |
2801 | /* These float cases don't actually occur as immediate operands. */ |
2802 | else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) | |
2803 | { | |
e9a25f70 JL |
2804 | REAL_VALUE_TYPE r; |
2805 | char dstr[30]; | |
2806 | ||
5f1ec3e6 JVA |
2807 | REAL_VALUE_FROM_CONST_DOUBLE (r, x); |
2808 | REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr); | |
2809 | fprintf (file, "%s", dstr); | |
2a2ab3f9 | 2810 | } |
e9a25f70 | 2811 | |
5f1ec3e6 | 2812 | else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode) |
2a2ab3f9 | 2813 | { |
e9a25f70 JL |
2814 | REAL_VALUE_TYPE r; |
2815 | char dstr[30]; | |
2816 | ||
5f1ec3e6 JVA |
2817 | REAL_VALUE_FROM_CONST_DOUBLE (r, x); |
2818 | REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr); | |
2819 | fprintf (file, "%s", dstr); | |
2a2ab3f9 | 2820 | } |
79325812 | 2821 | else |
2a2ab3f9 | 2822 | { |
4af3895e | 2823 | if (code != 'P') |
2a2ab3f9 | 2824 | { |
695dac07 | 2825 | if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) |
e075ae69 RH |
2826 | { |
2827 | if (ASSEMBLER_DIALECT == 0) | |
2828 | putc ('$', file); | |
2829 | } | |
2a2ab3f9 JVA |
2830 | else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF |
2831 | || GET_CODE (x) == LABEL_REF) | |
e075ae69 RH |
2832 | { |
2833 | if (ASSEMBLER_DIALECT == 0) | |
2834 | putc ('$', file); | |
2835 | else | |
2836 | fputs ("OFFSET FLAT:", file); | |
2837 | } | |
2a2ab3f9 | 2838 | } |
e075ae69 RH |
2839 | if (GET_CODE (x) == CONST_INT) |
2840 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); | |
2841 | else if (flag_pic) | |
2a2ab3f9 JVA |
2842 | output_pic_addr_const (file, x, code); |
2843 | else | |
2844 | output_addr_const (file, x); | |
2845 | } | |
2846 | } | |
2847 | \f | |
2848 | /* Print a memory operand whose address is ADDR. */ | |
2849 | ||
2850 | void | |
2851 | print_operand_address (file, addr) | |
2852 | FILE *file; | |
2853 | register rtx addr; | |
2854 | { | |
e075ae69 RH |
2855 | struct ix86_address parts; |
2856 | rtx base, index, disp; | |
2857 | int scale; | |
e9a25f70 | 2858 | |
e075ae69 RH |
2859 | if (! ix86_decompose_address (addr, &parts)) |
2860 | abort (); | |
e9a25f70 | 2861 | |
e075ae69 RH |
2862 | base = parts.base; |
2863 | index = parts.index; | |
2864 | disp = parts.disp; | |
2865 | scale = parts.scale; | |
e9a25f70 | 2866 | |
e075ae69 RH |
2867 | if (!base && !index) |
2868 | { | |
2869 | /* Displacement only requires special attention. */ | |
e9a25f70 | 2870 | |
e075ae69 | 2871 | if (GET_CODE (disp) == CONST_INT) |
2a2ab3f9 | 2872 | { |
e075ae69 RH |
2873 | if (ASSEMBLER_DIALECT != 0) |
2874 | fputs ("ds:", file); | |
2875 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr)); | |
2a2ab3f9 | 2876 | } |
e075ae69 RH |
2877 | else if (flag_pic) |
2878 | output_pic_addr_const (file, addr, 0); | |
2879 | else | |
2880 | output_addr_const (file, addr); | |
2881 | } | |
2882 | else | |
2883 | { | |
2884 | if (ASSEMBLER_DIALECT == 0) | |
2a2ab3f9 | 2885 | { |
e075ae69 | 2886 | if (disp) |
2a2ab3f9 | 2887 | { |
c399861d | 2888 | if (flag_pic) |
e075ae69 RH |
2889 | output_pic_addr_const (file, disp, 0); |
2890 | else if (GET_CODE (disp) == LABEL_REF) | |
2891 | output_asm_label (disp); | |
2a2ab3f9 | 2892 | else |
e075ae69 | 2893 | output_addr_const (file, disp); |
2a2ab3f9 JVA |
2894 | } |
2895 | ||
e075ae69 RH |
2896 | putc ('(', file); |
2897 | if (base) | |
2898 | PRINT_REG (base, 0, file); | |
2899 | if (index) | |
2a2ab3f9 | 2900 | { |
e075ae69 RH |
2901 | putc (',', file); |
2902 | PRINT_REG (index, 0, file); | |
2903 | if (scale != 1) | |
2904 | fprintf (file, ",%d", scale); | |
2a2ab3f9 | 2905 | } |
e075ae69 | 2906 | putc (')', file); |
2a2ab3f9 | 2907 | } |
2a2ab3f9 JVA |
2908 | else |
2909 | { | |
e075ae69 | 2910 | rtx offset = NULL_RTX; |
e9a25f70 | 2911 | |
e075ae69 RH |
2912 | if (disp) |
2913 | { | |
2914 | /* Pull out the offset of a symbol; print any symbol itself. */ | |
2915 | if (GET_CODE (disp) == CONST | |
2916 | && GET_CODE (XEXP (disp, 0)) == PLUS | |
2917 | && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT) | |
2918 | { | |
2919 | offset = XEXP (XEXP (disp, 0), 1); | |
2920 | disp = gen_rtx_CONST (VOIDmode, | |
2921 | XEXP (XEXP (disp, 0), 0)); | |
2922 | } | |
ce193852 | 2923 | |
e075ae69 RH |
2924 | if (flag_pic) |
2925 | output_pic_addr_const (file, disp, 0); | |
2926 | else if (GET_CODE (disp) == LABEL_REF) | |
2927 | output_asm_label (disp); | |
2928 | else if (GET_CODE (disp) == CONST_INT) | |
2929 | offset = disp; | |
2930 | else | |
2931 | output_addr_const (file, disp); | |
2932 | } | |
e9a25f70 | 2933 | |
e075ae69 RH |
2934 | putc ('[', file); |
2935 | if (base) | |
a8620236 | 2936 | { |
e075ae69 RH |
2937 | PRINT_REG (base, 0, file); |
2938 | if (offset) | |
2939 | { | |
2940 | if (INTVAL (offset) >= 0) | |
2941 | putc ('+', file); | |
2942 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (offset)); | |
2943 | } | |
a8620236 | 2944 | } |
e075ae69 RH |
2945 | else if (offset) |
2946 | fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (offset)); | |
2247a58c | 2947 | else |
e075ae69 | 2948 | putc ('0', file); |
e9a25f70 | 2949 | |
e075ae69 RH |
2950 | if (index) |
2951 | { | |
2952 | putc ('+', file); | |
2953 | PRINT_REG (index, 0, file); | |
2954 | if (scale != 1) | |
2955 | fprintf (file, "*%d", scale); | |
2956 | } | |
2957 | putc (']', file); | |
2958 | } | |
2a2ab3f9 JVA |
2959 | } |
2960 | } | |
2961 | \f | |
2962 | /* Split one or more DImode RTL references into pairs of SImode | |
2963 | references. The RTL can be REG, offsettable MEM, integer constant, or | |
2964 | CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to | |
2965 | split and "num" is its length. lo_half and hi_half are output arrays | |
2966 | that parallel "operands". */ | |
2967 | ||
2968 | void | |
2969 | split_di (operands, num, lo_half, hi_half) | |
2970 | rtx operands[]; | |
2971 | int num; | |
2972 | rtx lo_half[], hi_half[]; | |
2973 | { | |
2974 | while (num--) | |
2975 | { | |
57dbca5e | 2976 | rtx op = operands[num]; |
e075ae69 RH |
2977 | if (CONSTANT_P (op)) |
2978 | split_double (op, &lo_half[num], &hi_half[num]); | |
2979 | else if (! reload_completed) | |
a269a03c JC |
2980 | { |
2981 | lo_half[num] = gen_lowpart (SImode, op); | |
2982 | hi_half[num] = gen_highpart (SImode, op); | |
2983 | } | |
2984 | else if (GET_CODE (op) == REG) | |
2a2ab3f9 | 2985 | { |
57dbca5e BS |
2986 | lo_half[num] = gen_rtx_REG (SImode, REGNO (op)); |
2987 | hi_half[num] = gen_rtx_REG (SImode, REGNO (op) + 1); | |
2a2ab3f9 | 2988 | } |
57dbca5e | 2989 | else if (offsettable_memref_p (op)) |
2a2ab3f9 | 2990 | { |
57dbca5e BS |
2991 | rtx lo_addr = XEXP (op, 0); |
2992 | rtx hi_addr = XEXP (adj_offsettable_operand (op, 4), 0); | |
2993 | lo_half[num] = change_address (op, SImode, lo_addr); | |
2994 | hi_half[num] = change_address (op, SImode, hi_addr); | |
2a2ab3f9 JVA |
2995 | } |
2996 | else | |
2997 | abort(); | |
2998 | } | |
2999 | } | |
3000 | \f | |
2a2ab3f9 JVA |
3001 | /* Output code to perform a 387 binary operation in INSN, one of PLUS, |
3002 | MINUS, MULT or DIV. OPERANDS are the insn operands, where operands[3] | |
3003 | is the expression of the binary operation. The output may either be | |
3004 | emitted here, or returned to the caller, like all output_* functions. | |
3005 | ||
3006 | There is no guarantee that the operands are the same mode, as they | |
3007 | might be within FLOAT or FLOAT_EXTEND expressions. */ | |
3008 | ||
3009 | char * | |
3010 | output_387_binary_op (insn, operands) | |
3011 | rtx insn; | |
3012 | rtx *operands; | |
3013 | { | |
2a2ab3f9 | 3014 | static char buf[100]; |
e075ae69 RH |
3015 | rtx temp; |
3016 | char *p; | |
2a2ab3f9 JVA |
3017 | |
3018 | switch (GET_CODE (operands[3])) | |
3019 | { | |
3020 | case PLUS: | |
e075ae69 RH |
3021 | if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT |
3022 | || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) | |
3023 | p = "fiadd"; | |
3024 | else | |
3025 | p = "fadd"; | |
2a2ab3f9 JVA |
3026 | break; |
3027 | ||
3028 | case MINUS: | |
e075ae69 RH |
3029 | if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT |
3030 | || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) | |
3031 | p = "fisub"; | |
3032 | else | |
3033 | p = "fsub"; | |
2a2ab3f9 JVA |
3034 | break; |
3035 | ||
3036 | case MULT: | |
e075ae69 RH |
3037 | if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT |
3038 | || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) | |
3039 | p = "fimul"; | |
3040 | else | |
3041 | p = "fmul"; | |
2a2ab3f9 JVA |
3042 | break; |
3043 | ||
3044 | case DIV: | |
e075ae69 RH |
3045 | if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT |
3046 | || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT) | |
3047 | p = "fidiv"; | |
3048 | else | |
3049 | p = "fdiv"; | |
2a2ab3f9 JVA |
3050 | break; |
3051 | ||
3052 | default: | |
3053 | abort (); | |
3054 | } | |
3055 | ||
e075ae69 | 3056 | strcpy (buf, p); |
2a2ab3f9 JVA |
3057 | |
3058 | switch (GET_CODE (operands[3])) | |
3059 | { | |
3060 | case MULT: | |
3061 | case PLUS: | |
3062 | if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2])) | |
3063 | { | |
3064 | temp = operands[2]; | |
3065 | operands[2] = operands[1]; | |
3066 | operands[1] = temp; | |
3067 | } | |
3068 | ||
3069 | if (GET_CODE (operands[2]) == MEM) | |
e075ae69 RH |
3070 | { |
3071 | p = "%z2\t%2"; | |
3072 | break; | |
3073 | } | |
2a2ab3f9 JVA |
3074 | |
3075 | if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) | |
6b28fd63 JL |
3076 | { |
3077 | if (STACK_TOP_P (operands[0])) | |
e075ae69 | 3078 | p = "p\t{%0,%2|%2, %0}"; |
6b28fd63 | 3079 | else |
e075ae69 RH |
3080 | p = "p\t{%2,%0|%0, %2}"; |
3081 | break; | |
6b28fd63 | 3082 | } |
2a2ab3f9 JVA |
3083 | |
3084 | if (STACK_TOP_P (operands[0])) | |
e075ae69 | 3085 | p = "\t{%y2,%0|%0, %y2}"; |
2a2ab3f9 | 3086 | else |
e075ae69 RH |
3087 | p = "\t{%2,%0|%0, %2}"; |
3088 | break; | |
2a2ab3f9 JVA |
3089 | |
3090 | case MINUS: | |
3091 | case DIV: | |
3092 | if (GET_CODE (operands[1]) == MEM) | |
e075ae69 RH |
3093 | { |
3094 | p = "r%z1\t%1"; | |
3095 | break; | |
3096 | } | |
2a2ab3f9 JVA |
3097 | |
3098 | if (GET_CODE (operands[2]) == MEM) | |
e075ae69 RH |
3099 | { |
3100 | p = "%z2\t%2"; | |
3101 | break; | |
3102 | } | |
2a2ab3f9 | 3103 | |
2a2ab3f9 JVA |
3104 | if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2])) |
3105 | abort (); | |
3106 | ||
e075ae69 RH |
3107 | /* Note that the Unixware assembler, and the AT&T assembler before |
3108 | that, are confusingly not reversed from Intel syntax in this | |
3109 | area. */ | |
2a2ab3f9 | 3110 | if (find_regno_note (insn, REG_DEAD, REGNO (operands[2]))) |
6b28fd63 JL |
3111 | { |
3112 | if (STACK_TOP_P (operands[0])) | |
e075ae69 | 3113 | p = "p\t%0,%2"; |
6b28fd63 | 3114 | else |
e075ae69 RH |
3115 | p = "rp\t%2,%0"; |
3116 | break; | |
6b28fd63 | 3117 | } |
2a2ab3f9 JVA |
3118 | |
3119 | if (find_regno_note (insn, REG_DEAD, REGNO (operands[1]))) | |
6b28fd63 JL |
3120 | { |
3121 | if (STACK_TOP_P (operands[0])) | |
e075ae69 | 3122 | p = "rp\t%0,%1"; |
6b28fd63 | 3123 | else |
e075ae69 RH |
3124 | p = "p\t%1,%0"; |
3125 | break; | |
6b28fd63 | 3126 | } |
2a2ab3f9 JVA |
3127 | |
3128 | if (STACK_TOP_P (operands[0])) | |
3129 | { | |
3130 | if (STACK_TOP_P (operands[1])) | |
e075ae69 | 3131 | p = "\t%y2,%0"; |
2a2ab3f9 | 3132 | else |
e075ae69 RH |
3133 | p = "r\t%y1,%0"; |
3134 | break; | |
2a2ab3f9 JVA |
3135 | } |
3136 | else if (STACK_TOP_P (operands[1])) | |
e075ae69 | 3137 | p = "\t%1,%0"; |
2a2ab3f9 | 3138 | else |
e075ae69 RH |
3139 | p = "r\t%2,%0"; |
3140 | break; | |
2a2ab3f9 JVA |
3141 | |
3142 | default: | |
3143 | abort (); | |
3144 | } | |
e075ae69 RH |
3145 | |
3146 | strcat (buf, p); | |
3147 | return buf; | |
2a2ab3f9 | 3148 | } |
e075ae69 | 3149 | |
2a2ab3f9 | 3150 | /* Output code for INSN to convert a float to a signed int. OPERANDS |
e075ae69 RH |
3151 | are the insn operands. The output may be [SD]Imode and the input |
3152 | operand may be [SDX]Fmode. */ | |
2a2ab3f9 JVA |
3153 | |
3154 | char * | |
3155 | output_fix_trunc (insn, operands) | |
3156 | rtx insn; | |
3157 | rtx *operands; | |
3158 | { | |
3159 | int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; | |
e075ae69 RH |
3160 | int dimode_p = GET_MODE (operands[0]) == DImode; |
3161 | rtx xops[4]; | |
2a2ab3f9 | 3162 | |
e075ae69 RH |
3163 | /* Jump through a hoop or two for DImode, since the hardware has no |
3164 | non-popping instruction. We used to do this a different way, but | |
3165 | that was somewhat fragile and broke with post-reload splitters. */ | |
3166 | if (dimode_p) | |
3167 | { | |
3168 | if (! STACK_TOP_P (operands[1])) | |
3169 | { | |
3170 | rtx tmp; | |
3171 | ||
3172 | output_asm_insn ("fst\t%y1", operands); | |
2a2ab3f9 | 3173 | |
e075ae69 RH |
3174 | /* The scratch we allocated sure better have died. */ |
3175 | if (! stack_top_dies) | |
3176 | abort (); | |
3177 | ||
3178 | tmp = operands[1]; | |
3179 | operands[1] = operands[5]; | |
3180 | operands[5] = tmp; | |
3181 | } | |
3182 | else if (! stack_top_dies) | |
3183 | output_asm_insn ("fld\t%y1", operands); | |
3184 | } | |
3185 | ||
3186 | if (! STACK_TOP_P (operands[1])) | |
10195bd8 JW |
3187 | abort (); |
3188 | ||
e075ae69 RH |
3189 | xops[0] = GEN_INT (12); |
3190 | xops[1] = adj_offsettable_operand (operands[2], 1); | |
3191 | xops[1] = change_address (xops[1], QImode, NULL_RTX); | |
305f097e | 3192 | |
e075ae69 RH |
3193 | xops[2] = operands[0]; |
3194 | if (GET_CODE (operands[0]) != MEM) | |
3195 | xops[2] = operands[3]; | |
2a2ab3f9 | 3196 | |
e075ae69 RH |
3197 | output_asm_insn ("fnstcw\t%2", operands); |
3198 | output_asm_insn ("mov{l}\t{%2, %4|%4, %2}", operands); | |
3199 | output_asm_insn ("mov{b}\t{%0, %1|%1, %0}", xops); | |
3200 | output_asm_insn ("fldcw\t%2", operands); | |
3201 | output_asm_insn ("mov{l}\t{%4, %2|%2, %4}", operands); | |
e9a25f70 | 3202 | |
e075ae69 RH |
3203 | if (stack_top_dies || dimode_p) |
3204 | output_asm_insn ("fistp%z2\t%2", xops); | |
10195bd8 | 3205 | else |
e075ae69 RH |
3206 | output_asm_insn ("fist%z2\t%2", xops); |
3207 | ||
3208 | output_asm_insn ("fldcw\t%2", operands); | |
10195bd8 | 3209 | |
e075ae69 | 3210 | if (GET_CODE (operands[0]) != MEM) |
2a2ab3f9 | 3211 | { |
e075ae69 | 3212 | if (dimode_p) |
2e14a41b | 3213 | { |
e075ae69 RH |
3214 | split_di (operands+0, 1, xops+0, xops+1); |
3215 | split_di (operands+3, 1, xops+2, xops+3); | |
3216 | output_asm_insn ("mov{l}\t{%2, %0|%0, %2}", xops); | |
3217 | output_asm_insn ("mov{l}\t{%3, %1|%1, %3}", xops); | |
2e14a41b | 3218 | } |
e075ae69 RH |
3219 | else |
3220 | output_asm_insn ("mov{l}\t{%3,%0|%0, %3}", operands); | |
2a2ab3f9 | 3221 | } |
2a2ab3f9 | 3222 | |
e075ae69 | 3223 | return ""; |
2a2ab3f9 | 3224 | } |
cda749b1 | 3225 | |
e075ae69 RH |
3226 | /* Output code for INSN to compare OPERANDS. EFLAGS_P is 1 when fcomi |
3227 | should be used and 2 when fnstsw should be used. UNORDERED_P is true | |
3228 | when fucom should be used. */ | |
3229 | ||
3230 | char * | |
3231 | output_fp_compare (insn, operands, eflags_p, unordered_p) | |
cda749b1 JW |
3232 | rtx insn; |
3233 | rtx *operands; | |
e075ae69 | 3234 | int eflags_p, unordered_p; |
cda749b1 | 3235 | { |
e075ae69 RH |
3236 | int stack_top_dies; |
3237 | rtx cmp_op0 = operands[0]; | |
3238 | rtx cmp_op1 = operands[1]; | |
3239 | ||
3240 | if (eflags_p == 2) | |
3241 | { | |
3242 | cmp_op0 = cmp_op1; | |
3243 | cmp_op1 = operands[2]; | |
3244 | } | |
cda749b1 | 3245 | |
e075ae69 | 3246 | if (! STACK_TOP_P (cmp_op0)) |
cda749b1 JW |
3247 | abort (); |
3248 | ||
e075ae69 | 3249 | stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; |
cda749b1 | 3250 | |
e075ae69 RH |
3251 | if (STACK_REG_P (cmp_op1) |
3252 | && stack_top_dies | |
3253 | && find_regno_note (insn, REG_DEAD, REGNO (cmp_op1)) | |
3254 | && REGNO (cmp_op1) != FIRST_STACK_REG) | |
cda749b1 | 3255 | { |
e075ae69 RH |
3256 | /* If both the top of the 387 stack dies, and the other operand |
3257 | is also a stack register that dies, then this must be a | |
3258 | `fcompp' float compare */ | |
3259 | ||
3260 | if (eflags_p == 1) | |
3261 | { | |
3262 | /* There is no double popping fcomi variant. Fortunately, | |
3263 | eflags is immune from the fstp's cc clobbering. */ | |
3264 | if (unordered_p) | |
3265 | output_asm_insn ("fucomip\t{%y1, %0|%0, %y1}", operands); | |
3266 | else | |
3267 | output_asm_insn ("fcomip\t{%y1, %0|%0, %y1}", operands); | |
3268 | return "fstp\t%y0"; | |
3269 | } | |
3270 | else | |
cda749b1 | 3271 | { |
e075ae69 RH |
3272 | if (eflags_p == 2) |
3273 | { | |
3274 | if (unordered_p) | |
3275 | return "fucompp\n\tfnstsw\t%0"; | |
3276 | else | |
3277 | return "fcompp\n\tfnstsw\t%0"; | |
3278 | } | |
cda749b1 JW |
3279 | else |
3280 | { | |
e075ae69 RH |
3281 | if (unordered_p) |
3282 | return "fucompp"; | |
3283 | else | |
3284 | return "fcompp"; | |
cda749b1 JW |
3285 | } |
3286 | } | |
cda749b1 JW |
3287 | } |
3288 | else | |
3289 | { | |
e075ae69 | 3290 | /* Encoded here as eflags_p | intmode | unordered_p | stack_top_dies. */ |
cda749b1 | 3291 | |
e075ae69 RH |
3292 | static char * const alt[24] = |
3293 | { | |
3294 | "fcom%z1\t%y1", | |
3295 | "fcomp%z1\t%y1", | |
3296 | "fucom%z1\t%y1", | |
3297 | "fucomp%z1\t%y1", | |
3298 | ||
3299 | "ficom%z1\t%y1", | |
3300 | "ficomp%z1\t%y1", | |
3301 | NULL, | |
3302 | NULL, | |
3303 | ||
3304 | "fcomi\t{%y1, %0|%0, %y1}", | |
3305 | "fcomip\t{%y1, %0|%0, %y1}", | |
3306 | "fucomi\t{%y1, %0|%0, %y1}", | |
3307 | "fucomip\t{%y1, %0|%0, %y1}", | |
3308 | ||
3309 | NULL, | |
3310 | NULL, | |
3311 | NULL, | |
3312 | NULL, | |
3313 | ||
3314 | "fcom%z2\t%y2\n\tfnstsw\t%0", | |
3315 | "fcomp%z2\t%y2\n\tfnstsw\t%0", | |
3316 | "fucom%z2\t%y2\n\tfnstsw\t%0", | |
3317 | "fucomp%z2\t%y2\n\tfnstsw\t%0", | |
3318 | ||
3319 | "ficom%z2\t%y2\n\tfnstsw\t%0", | |
3320 | "ficomp%z2\t%y2\n\tfnstsw\t%0", | |
3321 | NULL, | |
3322 | NULL | |
3323 | }; | |
3324 | ||
3325 | int mask; | |
3326 | char *ret; | |
3327 | ||
3328 | mask = eflags_p << 3; | |
3329 | mask |= (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT) << 2; | |
3330 | mask |= unordered_p << 1; | |
3331 | mask |= stack_top_dies; | |
3332 | ||
3333 | if (mask >= 24) | |
3334 | abort (); | |
3335 | ret = alt[mask]; | |
3336 | if (ret == NULL) | |
3337 | abort (); | |
cda749b1 | 3338 | |
e075ae69 | 3339 | return ret; |
cda749b1 JW |
3340 | } |
3341 | } | |
2a2ab3f9 | 3342 | |
e075ae69 | 3343 | /* Output assembler code to FILE to initialize basic-block profiling. |
2a2ab3f9 | 3344 | |
e075ae69 | 3345 | If profile_block_flag == 2 |
2a2ab3f9 | 3346 | |
e075ae69 RH |
3347 | Output code to call the subroutine `__bb_init_trace_func' |
3348 | and pass two parameters to it. The first parameter is | |
3349 | the address of a block allocated in the object module. | |
3350 | The second parameter is the number of the first basic block | |
3351 | of the function. | |
2a2ab3f9 | 3352 | |
e075ae69 RH |
3353 | The name of the block is a local symbol made with this statement: |
3354 | ||
3355 | ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0); | |
2a2ab3f9 | 3356 | |
e075ae69 RH |
3357 | Of course, since you are writing the definition of |
3358 | `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you | |
3359 | can take a short cut in the definition of this macro and use the | |
3360 | name that you know will result. | |
2a2ab3f9 | 3361 | |
e075ae69 RH |
3362 | The number of the first basic block of the function is |
3363 | passed to the macro in BLOCK_OR_LABEL. | |
2a2ab3f9 | 3364 | |
e075ae69 RH |
3365 | If described in a virtual assembler language the code to be |
3366 | output looks like: | |
2a2ab3f9 | 3367 | |
e075ae69 RH |
3368 | parameter1 <- LPBX0 |
3369 | parameter2 <- BLOCK_OR_LABEL | |
3370 | call __bb_init_trace_func | |
2a2ab3f9 | 3371 | |
e075ae69 | 3372 | else if profile_block_flag != 0 |
e74389ff | 3373 | |
e075ae69 RH |
3374 | Output code to call the subroutine `__bb_init_func' |
3375 | and pass one single parameter to it, which is the same | |
3376 | as the first parameter to `__bb_init_trace_func'. | |
e74389ff | 3377 | |
e075ae69 RH |
3378 | The first word of this parameter is a flag which will be nonzero if |
3379 | the object module has already been initialized. So test this word | |
3380 | first, and do not call `__bb_init_func' if the flag is nonzero. | |
3381 | Note: When profile_block_flag == 2 the test need not be done | |
3382 | but `__bb_init_trace_func' *must* be called. | |
e74389ff | 3383 | |
e075ae69 RH |
3384 | BLOCK_OR_LABEL may be used to generate a label number as a |
3385 | branch destination in case `__bb_init_func' will not be called. | |
e74389ff | 3386 | |
e075ae69 RH |
3387 | If described in a virtual assembler language the code to be |
3388 | output looks like: | |
2a2ab3f9 | 3389 | |
e075ae69 RH |
3390 | cmp (LPBX0),0 |
3391 | jne local_label | |
3392 | parameter1 <- LPBX0 | |
3393 | call __bb_init_func | |
3394 | local_label: | |
3395 | */ | |
c572e5ba | 3396 | |
e075ae69 RH |
3397 | void |
3398 | ix86_output_function_block_profiler (file, block_or_label) | |
3399 | FILE *file; | |
3400 | int block_or_label; | |
c572e5ba | 3401 | { |
e075ae69 RH |
3402 | static int num_func = 0; |
3403 | rtx xops[8]; | |
3404 | char block_table[80], false_label[80]; | |
c572e5ba | 3405 | |
e075ae69 | 3406 | ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); |
e9a25f70 | 3407 | |
e075ae69 RH |
3408 | xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table); |
3409 | xops[5] = stack_pointer_rtx; | |
3410 | xops[7] = gen_rtx_REG (Pmode, 0); /* eax */ | |
2a2ab3f9 | 3411 | |
e075ae69 | 3412 | CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; |
c572e5ba | 3413 | |
e075ae69 | 3414 | switch (profile_block_flag) |
c572e5ba | 3415 | { |
e075ae69 RH |
3416 | case 2: |
3417 | xops[2] = GEN_INT (block_or_label); | |
3418 | xops[3] = gen_rtx_MEM (Pmode, | |
3419 | gen_rtx_SYMBOL_REF (VOIDmode, "__bb_init_trace_func")); | |
3420 | xops[6] = GEN_INT (8); | |
e9a25f70 | 3421 | |
e075ae69 RH |
3422 | output_asm_insn ("push{l}\t%2", xops); |
3423 | if (!flag_pic) | |
3424 | output_asm_insn ("push{l}\t%1", xops); | |
e9a25f70 | 3425 | else |
870a0c2c | 3426 | { |
e075ae69 RH |
3427 | output_asm_insn ("lea{l}\t{%a1, %7|%7, %a1}", xops); |
3428 | output_asm_insn ("push{l}\t%7", xops); | |
870a0c2c | 3429 | } |
e075ae69 RH |
3430 | output_asm_insn ("call\t%P3", xops); |
3431 | output_asm_insn ("add{l}\t{%6, %5|%5, %6}", xops); | |
3432 | break; | |
c572e5ba | 3433 | |
e075ae69 RH |
3434 | default: |
3435 | ASM_GENERATE_INTERNAL_LABEL (false_label, "LPBZ", num_func); | |
c572e5ba | 3436 | |
e075ae69 RH |
3437 | xops[0] = const0_rtx; |
3438 | xops[2] = gen_rtx_MEM (Pmode, | |
3439 | gen_rtx_SYMBOL_REF (VOIDmode, false_label)); | |
3440 | xops[3] = gen_rtx_MEM (Pmode, | |
3441 | gen_rtx_SYMBOL_REF (VOIDmode, "__bb_init_func")); | |
3442 | xops[4] = gen_rtx_MEM (Pmode, xops[1]); | |
3443 | xops[6] = GEN_INT (4); | |
a14003ee | 3444 | |
e075ae69 | 3445 | CONSTANT_POOL_ADDRESS_P (xops[2]) = TRUE; |
446ba526 | 3446 | |
e075ae69 RH |
3447 | output_asm_insn ("cmp{l}\t{%0, %4|%4, %0}", xops); |
3448 | output_asm_insn ("jne\t%2", xops); | |
870a0c2c | 3449 | |
e075ae69 RH |
3450 | if (!flag_pic) |
3451 | output_asm_insn ("push{l}\t%1", xops); | |
3452 | else | |
3453 | { | |
3454 | output_asm_insn ("lea{l}\t{%a1, %7|%7, %a2}", xops); | |
3455 | output_asm_insn ("push{l}\t%7", xops); | |
870a0c2c | 3456 | } |
e075ae69 RH |
3457 | output_asm_insn ("call\t%P3", xops); |
3458 | output_asm_insn ("add{l}\t{%6, %5|%5, %6}", xops); | |
3459 | ASM_OUTPUT_INTERNAL_LABEL (file, "LPBZ", num_func); | |
3460 | num_func++; | |
3461 | break; | |
c572e5ba | 3462 | } |
2a2ab3f9 | 3463 | } |
305f097e | 3464 | |
e075ae69 RH |
3465 | /* Output assembler code to FILE to increment a counter associated |
3466 | with basic block number BLOCKNO. | |
305f097e | 3467 | |
e075ae69 | 3468 | If profile_block_flag == 2 |
ecbc4695 | 3469 | |
e075ae69 RH |
3470 | Output code to initialize the global structure `__bb' and |
3471 | call the function `__bb_trace_func' which will increment the | |
3472 | counter. | |
ecbc4695 | 3473 | |
e075ae69 RH |
3474 | `__bb' consists of two words. In the first word the number |
3475 | of the basic block has to be stored. In the second word | |
3476 | the address of a block allocated in the object module | |
3477 | has to be stored. | |
ecbc4695 | 3478 | |
e075ae69 | 3479 | The basic block number is given by BLOCKNO. |
ecbc4695 | 3480 | |
e075ae69 | 3481 | The address of the block is given by the label created with |
305f097e | 3482 | |
e075ae69 | 3483 | ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0); |
305f097e | 3484 | |
e075ae69 | 3485 | by FUNCTION_BLOCK_PROFILER. |
ecbc4695 | 3486 | |
e075ae69 RH |
3487 | Of course, since you are writing the definition of |
3488 | `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you | |
3489 | can take a short cut in the definition of this macro and use the | |
3490 | name that you know will result. | |
305f097e | 3491 | |
e075ae69 RH |
3492 | If described in a virtual assembler language the code to be |
3493 | output looks like: | |
305f097e | 3494 | |
e075ae69 RH |
3495 | move BLOCKNO -> (__bb) |
3496 | move LPBX0 -> (__bb+4) | |
3497 | call __bb_trace_func | |
305f097e | 3498 | |
e075ae69 RH |
3499 | Note that function `__bb_trace_func' must not change the |
3500 | machine state, especially the flag register. To grant | |
3501 | this, you must output code to save and restore registers | |
3502 | either in this macro or in the macros MACHINE_STATE_SAVE | |
3503 | and MACHINE_STATE_RESTORE. The last two macros will be | |
3504 | used in the function `__bb_trace_func', so you must make | |
3505 | sure that the function prologue does not change any | |
3506 | register prior to saving it with MACHINE_STATE_SAVE. | |
305f097e | 3507 | |
e075ae69 | 3508 | else if profile_block_flag != 0 |
305f097e | 3509 | |
e075ae69 RH |
3510 | Output code to increment the counter directly. |
3511 | Basic blocks are numbered separately from zero within each | |
3512 | compiled object module. The count associated with block number | |
3513 | BLOCKNO is at index BLOCKNO in an array of words; the name of | |
3514 | this array is a local symbol made with this statement: | |
32b5b1aa | 3515 | |
e075ae69 | 3516 | ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2); |
32b5b1aa | 3517 | |
e075ae69 RH |
3518 | Of course, since you are writing the definition of |
3519 | `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you | |
3520 | can take a short cut in the definition of this macro and use the | |
3521 | name that you know will result. | |
32b5b1aa | 3522 | |
e075ae69 RH |
3523 | If described in a virtual assembler language the code to be |
3524 | output looks like: | |
32b5b1aa | 3525 | |
e075ae69 RH |
3526 | inc (LPBX2+4*BLOCKNO) |
3527 | */ | |
32b5b1aa | 3528 | |
e075ae69 RH |
3529 | void |
3530 | ix86_output_block_profiler (file, blockno) | |
3531 | FILE *file ATTRIBUTE_UNUSED; | |
3532 | int blockno; | |
3533 | { | |
3534 | rtx xops[8], cnt_rtx; | |
3535 | char counts[80]; | |
3536 | char *block_table = counts; | |
3537 | ||
3538 | switch (profile_block_flag) | |
3539 | { | |
3540 | case 2: | |
3541 | ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); | |
32b5b1aa | 3542 | |
e075ae69 RH |
3543 | xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table); |
3544 | xops[2] = GEN_INT (blockno); | |
3545 | xops[3] = gen_rtx_MEM (Pmode, | |
3546 | gen_rtx_SYMBOL_REF (VOIDmode, "__bb_trace_func")); | |
3547 | xops[4] = gen_rtx_SYMBOL_REF (VOIDmode, "__bb"); | |
3548 | xops[5] = plus_constant (xops[4], 4); | |
3549 | xops[0] = gen_rtx_MEM (SImode, xops[4]); | |
3550 | xops[6] = gen_rtx_MEM (SImode, xops[5]); | |
79325812 | 3551 | |
e075ae69 | 3552 | CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; |
32b5b1aa | 3553 | |
e075ae69 RH |
3554 | output_asm_insn ("pushf", xops); |
3555 | output_asm_insn ("mov{l}\t{%2, %0|%0, %2}", xops); | |
3556 | if (flag_pic) | |
32b5b1aa | 3557 | { |
e075ae69 RH |
3558 | xops[7] = gen_rtx_REG (Pmode, 0); /* eax */ |
3559 | output_asm_insn ("push{l}\t%7", xops); | |
3560 | output_asm_insn ("lea{l}\t{%a1, %7|%7, %a1}", xops); | |
3561 | output_asm_insn ("mov{l}\t{%7, %6|%6, %7}", xops); | |
3562 | output_asm_insn ("pop{l}\t%7", xops); | |
3563 | } | |
3564 | else | |
3565 | output_asm_insn ("mov{l}\t{%1, %6|%6, %1}", xops); | |
3566 | output_asm_insn ("call\t%P3", xops); | |
3567 | output_asm_insn ("popf", xops); | |
32b5b1aa | 3568 | |
e075ae69 | 3569 | break; |
32b5b1aa | 3570 | |
e075ae69 RH |
3571 | default: |
3572 | ASM_GENERATE_INTERNAL_LABEL (counts, "LPBX", 2); | |
3573 | cnt_rtx = gen_rtx_SYMBOL_REF (VOIDmode, counts); | |
3574 | SYMBOL_REF_FLAG (cnt_rtx) = TRUE; | |
32b5b1aa | 3575 | |
e075ae69 RH |
3576 | if (blockno) |
3577 | cnt_rtx = plus_constant (cnt_rtx, blockno*4); | |
32b5b1aa | 3578 | |
e075ae69 RH |
3579 | if (flag_pic) |
3580 | cnt_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, cnt_rtx); | |
32b5b1aa | 3581 | |
e075ae69 RH |
3582 | xops[0] = gen_rtx_MEM (SImode, cnt_rtx); |
3583 | output_asm_insn ("inc{l}\t%0", xops); | |
32b5b1aa | 3584 | |
e075ae69 | 3585 | break; |
32b5b1aa | 3586 | } |
32b5b1aa | 3587 | } |
32b5b1aa | 3588 | \f |
79325812 | 3589 | void |
e075ae69 RH |
3590 | ix86_expand_move (mode, operands) |
3591 | enum machine_mode mode; | |
3592 | rtx operands[]; | |
32b5b1aa | 3593 | { |
e075ae69 RH |
3594 | int strict = (reload_in_progress || reload_completed); |
3595 | int want_clobber = 0; | |
3596 | rtx insn; | |
e9a25f70 | 3597 | |
e075ae69 | 3598 | if (flag_pic && mode == Pmode && symbolic_operand (operands[1], Pmode)) |
32b5b1aa | 3599 | { |
e075ae69 | 3600 | /* Emit insns to move operands[1] into operands[0]. */ |
e9a25f70 | 3601 | |
e075ae69 RH |
3602 | if (GET_CODE (operands[0]) == MEM) |
3603 | operands[1] = force_reg (Pmode, operands[1]); | |
3604 | else | |
32b5b1aa | 3605 | { |
e075ae69 RH |
3606 | rtx temp = operands[0]; |
3607 | if (GET_CODE (temp) != REG) | |
3608 | temp = gen_reg_rtx (Pmode); | |
3609 | temp = legitimize_pic_address (operands[1], temp); | |
3610 | if (temp == operands[0]) | |
3611 | return; | |
3612 | operands[1] = temp; | |
32b5b1aa | 3613 | } |
e075ae69 RH |
3614 | } |
3615 | else | |
3616 | { | |
3617 | if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) | |
3618 | operands[1] = force_reg (mode, operands[1]); | |
e9a25f70 | 3619 | |
e075ae69 | 3620 | if (FLOAT_MODE_P (mode)) |
32b5b1aa | 3621 | { |
e075ae69 RH |
3622 | /* If we are loading a floating point constant that isn't 0 or 1 |
3623 | into a register, force the value to memory now, since we'll | |
3624 | get better code out the back end. */ | |
3625 | ||
3626 | if (strict) | |
3627 | ; | |
3628 | else if (GET_CODE (operands[0]) == MEM) | |
3629 | operands[1] = force_reg (mode, operands[1]); | |
3630 | else if (GET_CODE (operands[1]) == CONST_DOUBLE | |
3631 | && ! standard_80387_constant_p (operands[1])) | |
3632 | operands[1] = validize_mem (force_const_mem (mode, operands[1])); | |
32b5b1aa SC |
3633 | } |
3634 | else | |
3635 | { | |
e075ae69 RH |
3636 | /* Try to guess when a cc clobber on the move might be fruitful. */ |
3637 | if (!strict | |
3638 | && GET_CODE (operands[0]) == REG | |
3639 | && operands[1] == const0_rtx | |
3640 | && !flag_peephole2) | |
3641 | want_clobber = 1; | |
32b5b1aa SC |
3642 | } |
3643 | } | |
e9a25f70 | 3644 | |
e075ae69 RH |
3645 | insn = gen_rtx_SET (VOIDmode, operands[0], operands[1]); |
3646 | if (want_clobber) | |
32b5b1aa | 3647 | { |
e075ae69 RH |
3648 | rtx clob; |
3649 | clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); | |
3650 | insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, insn, clob)); | |
32b5b1aa | 3651 | } |
e9a25f70 | 3652 | |
e075ae69 RH |
3653 | emit_insn (insn); |
3654 | } | |
e9a25f70 | 3655 | |
e075ae69 RH |
3656 | /* Attempt to expand a binary operator. Make the expansion closer to the |
3657 | actual machine, then just general_operand, which will allow 3 separate | |
3658 | memory references (one output, two input) in a single insn. Return | |
3659 | whether the insn fails, or succeeds. */ | |
e9a25f70 | 3660 | |
e075ae69 RH |
3661 | void |
3662 | ix86_expand_binary_operator (code, mode, operands) | |
3663 | enum rtx_code code; | |
3664 | enum machine_mode mode; | |
3665 | rtx operands[]; | |
3666 | { | |
3667 | int matching_memory; | |
3668 | rtx src1, src2, dst, op, clob; | |
3669 | ||
3670 | dst = operands[0]; | |
3671 | src1 = operands[1]; | |
3672 | src2 = operands[2]; | |
3673 | ||
3674 | /* Recognize <var1> = <value> <op> <var1> for commutative operators */ | |
3675 | if (GET_RTX_CLASS (code) == 'c' | |
3676 | && (rtx_equal_p (dst, src2) | |
3677 | || immediate_operand (src1, mode))) | |
3678 | { | |
3679 | rtx temp = src1; | |
3680 | src1 = src2; | |
3681 | src2 = temp; | |
32b5b1aa | 3682 | } |
e9a25f70 | 3683 | |
e075ae69 RH |
3684 | /* If the destination is memory, and we do not have matching source |
3685 | operands, do things in registers. */ | |
3686 | matching_memory = 0; | |
3687 | if (GET_CODE (dst) == MEM) | |
32b5b1aa | 3688 | { |
e075ae69 RH |
3689 | if (rtx_equal_p (dst, src1)) |
3690 | matching_memory = 1; | |
3691 | else if (GET_RTX_CLASS (code) == 'c' | |
3692 | && rtx_equal_p (dst, src2)) | |
3693 | matching_memory = 2; | |
3694 | else | |
3695 | dst = gen_reg_rtx (mode); | |
3696 | } | |
3697 | ||
3698 | /* Both source operands cannot be in memory. */ | |
3699 | if (GET_CODE (src1) == MEM && GET_CODE (src2) == MEM) | |
3700 | { | |
3701 | if (matching_memory != 2) | |
3702 | src2 = force_reg (mode, src2); | |
3703 | else | |
3704 | src1 = force_reg (mode, src1); | |
32b5b1aa | 3705 | } |
e9a25f70 | 3706 | |
e075ae69 RH |
3707 | /* If the operation is not commutable, source 1 cannot be a constant. */ |
3708 | if (CONSTANT_P (src1) && GET_RTX_CLASS (code) != 'c') | |
3709 | src1 = force_reg (mode, src1); | |
3710 | ||
3711 | /* If optimizing, copy to regs to improve CSE */ | |
3712 | if (optimize && !reload_in_progress && !reload_completed) | |
32b5b1aa | 3713 | { |
e075ae69 RH |
3714 | if (GET_CODE (dst) == MEM) |
3715 | dst = gen_reg_rtx (mode); | |
3716 | if (GET_CODE (src1) == MEM) | |
3717 | src1 = force_reg (mode, src1); | |
3718 | if (GET_CODE (src2) == MEM) | |
3719 | src2 = force_reg (mode, src2); | |
32b5b1aa | 3720 | } |
e9a25f70 | 3721 | |
e075ae69 RH |
3722 | /* Emit the instruction. */ |
3723 | ||
3724 | op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_ee (code, mode, src1, src2)); | |
3725 | if (reload_in_progress) | |
3726 | { | |
3727 | /* Reload doesn't know about the flags register, and doesn't know that | |
3728 | it doesn't want to clobber it. We can only do this with PLUS. */ | |
3729 | if (code != PLUS) | |
3730 | abort (); | |
3731 | emit_insn (op); | |
3732 | } | |
3733 | else | |
32b5b1aa | 3734 | { |
e075ae69 RH |
3735 | clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); |
3736 | emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob))); | |
32b5b1aa | 3737 | } |
e9a25f70 | 3738 | |
e075ae69 RH |
3739 | /* Fix up the destination if needed. */ |
3740 | if (dst != operands[0]) | |
3741 | emit_move_insn (operands[0], dst); | |
3742 | } | |
3743 | ||
3744 | /* Return TRUE or FALSE depending on whether the binary operator meets the | |
3745 | appropriate constraints. */ | |
3746 | ||
3747 | int | |
3748 | ix86_binary_operator_ok (code, mode, operands) | |
3749 | enum rtx_code code; | |
3750 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
3751 | rtx operands[3]; | |
3752 | { | |
3753 | /* Both source operands cannot be in memory. */ | |
3754 | if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[2]) == MEM) | |
3755 | return 0; | |
3756 | /* If the operation is not commutable, source 1 cannot be a constant. */ | |
3757 | if (CONSTANT_P (operands[1]) && GET_RTX_CLASS (code) != 'c') | |
3758 | return 0; | |
3759 | /* If the destination is memory, we must have a matching source operand. */ | |
3760 | if (GET_CODE (operands[0]) == MEM | |
3761 | && ! (rtx_equal_p (operands[0], operands[1]) | |
3762 | || (GET_RTX_CLASS (code) == 'c' | |
3763 | && rtx_equal_p (operands[0], operands[2])))) | |
3764 | return 0; | |
3765 | return 1; | |
3766 | } | |
3767 | ||
3768 | /* Attempt to expand a unary operator. Make the expansion closer to the | |
3769 | actual machine, then just general_operand, which will allow 2 separate | |
3770 | memory references (one output, one input) in a single insn. Return | |
3771 | whether the insn fails, or succeeds. */ | |
3772 | ||
3773 | int | |
3774 | ix86_expand_unary_operator (code, mode, operands) | |
3775 | enum rtx_code code; | |
3776 | enum machine_mode mode; | |
3777 | rtx operands[]; | |
3778 | { | |
3779 | /* If optimizing, copy to regs to improve CSE */ | |
3780 | if (optimize | |
3781 | && ((reload_in_progress | reload_completed) == 0) | |
3782 | && GET_CODE (operands[1]) == MEM) | |
3783 | operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); | |
3784 | ||
3785 | if (! ix86_unary_operator_ok (code, mode, operands)) | |
32b5b1aa | 3786 | { |
e075ae69 RH |
3787 | if (optimize == 0 |
3788 | && ((reload_in_progress | reload_completed) == 0) | |
3789 | && GET_CODE (operands[1]) == MEM) | |
32b5b1aa | 3790 | { |
e075ae69 RH |
3791 | operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); |
3792 | if (! ix86_unary_operator_ok (code, mode, operands)) | |
3793 | return FALSE; | |
32b5b1aa | 3794 | } |
e075ae69 RH |
3795 | else |
3796 | return FALSE; | |
32b5b1aa | 3797 | } |
e9a25f70 | 3798 | |
e075ae69 RH |
3799 | return TRUE; |
3800 | } | |
3801 | ||
3802 | /* Return TRUE or FALSE depending on whether the unary operator meets the | |
3803 | appropriate constraints. */ | |
3804 | ||
3805 | int | |
3806 | ix86_unary_operator_ok (code, mode, operands) | |
3807 | enum rtx_code code ATTRIBUTE_UNUSED; | |
3808 | enum machine_mode mode ATTRIBUTE_UNUSED; | |
3809 | rtx operands[2] ATTRIBUTE_UNUSED; | |
3810 | { | |
3811 | return TRUE; | |
3812 | } | |
3813 | ||
3814 | /* Produce an unsigned comparison for a given signed comparison. */ | |
3815 | ||
3816 | static enum rtx_code | |
3817 | unsigned_comparison (code) | |
3818 | enum rtx_code code; | |
3819 | { | |
3820 | switch (code) | |
32b5b1aa | 3821 | { |
e075ae69 RH |
3822 | case GT: |
3823 | code = GTU; | |
3824 | break; | |
3825 | case LT: | |
3826 | code = LTU; | |
3827 | break; | |
3828 | case GE: | |
3829 | code = GEU; | |
3830 | break; | |
3831 | case LE: | |
3832 | code = LEU; | |
3833 | break; | |
3834 | case EQ: | |
3835 | case NE: | |
3836 | case LEU: | |
3837 | case LTU: | |
3838 | case GEU: | |
3839 | case GTU: | |
3840 | break; | |
3841 | default: | |
3842 | abort (); | |
3843 | } | |
3844 | return code; | |
3845 | } | |
3846 | ||
3847 | /* Generate insn patterns to do an integer compare of OPERANDS. */ | |
3848 | ||
3849 | static rtx | |
3850 | ix86_expand_int_compare (code, op0, op1) | |
3851 | enum rtx_code code; | |
3852 | rtx op0, op1; | |
3853 | { | |
3854 | enum machine_mode cmpmode; | |
3855 | rtx tmp, flags; | |
3856 | ||
3857 | cmpmode = SELECT_CC_MODE (code, op0, op1); | |
3858 | flags = gen_rtx_REG (cmpmode, FLAGS_REG); | |
3859 | ||
3860 | /* This is very simple, but making the interface the same as in the | |
3861 | FP case makes the rest of the code easier. */ | |
3862 | tmp = gen_rtx_COMPARE (cmpmode, op0, op1); | |
3863 | emit_insn (gen_rtx_SET (VOIDmode, flags, tmp)); | |
3864 | ||
3865 | /* Return the test that should be put into the flags user, i.e. | |
3866 | the bcc, scc, or cmov instruction. */ | |
3867 | return gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx); | |
3868 | } | |
3869 | ||
3870 | /* Generate insn patterns to do a floating point compare of OPERANDS. | |
3871 | If UNORDERED, allow for unordered compares. */ | |
3872 | ||
3873 | static rtx | |
3874 | ix86_expand_fp_compare (code, op0, op1, unordered) | |
3875 | enum rtx_code code; | |
3876 | rtx op0, op1; | |
3877 | int unordered; | |
3878 | { | |
3879 | enum machine_mode fpcmp_mode; | |
3880 | enum machine_mode intcmp_mode; | |
3881 | rtx tmp; | |
3882 | ||
3883 | /* When not doing IEEE compliant compares, disable unordered. */ | |
3884 | if (! TARGET_IEEE_FP) | |
3885 | unordered = 0; | |
3886 | fpcmp_mode = unordered ? CCFPUmode : CCFPmode; | |
3887 | ||
3888 | /* ??? If we knew whether invalid-operand exceptions were masked, | |
3889 | we could rely on fcom to raise an exception and take care of | |
3890 | NaNs. But we don't. We could know this from c9x math bits. */ | |
3891 | if (TARGET_IEEE_FP) | |
3892 | unordered = 1; | |
3893 | ||
3894 | /* All of the unordered compare instructions only work on registers. | |
3895 | The same is true of the XFmode compare instructions. */ | |
3896 | if (unordered || GET_MODE (op0) == XFmode) | |
3897 | { | |
3898 | op0 = force_reg (GET_MODE (op0), op0); | |
3899 | op1 = force_reg (GET_MODE (op1), op1); | |
3900 | } | |
3901 | else | |
3902 | { | |
3903 | /* %%% We only allow op1 in memory; op0 must be st(0). So swap | |
3904 | things around if they appear profitable, otherwise force op0 | |
3905 | into a register. */ | |
3906 | ||
3907 | if (standard_80387_constant_p (op0) == 0 | |
3908 | || (GET_CODE (op0) == MEM | |
3909 | && ! (standard_80387_constant_p (op1) == 0 | |
3910 | || GET_CODE (op1) == MEM))) | |
32b5b1aa | 3911 | { |
e075ae69 RH |
3912 | rtx tmp; |
3913 | tmp = op0, op0 = op1, op1 = tmp; | |
3914 | code = swap_condition (code); | |
3915 | } | |
3916 | ||
3917 | if (GET_CODE (op0) != REG) | |
3918 | op0 = force_reg (GET_MODE (op0), op0); | |
3919 | ||
3920 | if (CONSTANT_P (op1)) | |
3921 | { | |
3922 | if (standard_80387_constant_p (op1)) | |
3923 | op1 = force_reg (GET_MODE (op1), op1); | |
3924 | else | |
3925 | op1 = validize_mem (force_const_mem (GET_MODE (op1), op1)); | |
32b5b1aa SC |
3926 | } |
3927 | } | |
e9a25f70 | 3928 | |
e075ae69 RH |
3929 | /* %%% fcomi is probably always faster, even when dealing with memory, |
3930 | since compare-and-branch would be three insns instead of four. */ | |
3931 | if (TARGET_CMOVE && !unordered) | |
32b5b1aa | 3932 | { |
e075ae69 RH |
3933 | if (GET_CODE (op0) != REG) |
3934 | op0 = force_reg (GET_MODE (op0), op0); | |
3935 | if (GET_CODE (op1) != REG) | |
3936 | op1 = force_reg (GET_MODE (op1), op1); | |
3937 | ||
3938 | tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1); | |
3939 | tmp = gen_rtx_SET (VOIDmode, gen_rtx_REG (fpcmp_mode, FLAGS_REG), tmp); | |
3940 | emit_insn (tmp); | |
3941 | ||
3942 | /* The FP codes work out to act like unsigned. */ | |
3943 | code = unsigned_comparison (code); | |
3944 | intcmp_mode = fpcmp_mode; | |
3945 | } | |
3946 | else | |
3947 | { | |
3948 | /* Sadness wrt reg-stack pops killing fpsr -- gotta get fnstsw first. */ | |
e9a25f70 | 3949 | |
e075ae69 RH |
3950 | rtx tmp2; |
3951 | tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1); | |
3952 | tmp2 = gen_rtx_UNSPEC (HImode, gen_rtvec (1, tmp), 9); | |
3953 | tmp = gen_reg_rtx (HImode); | |
3954 | emit_insn (gen_rtx_SET (VOIDmode, tmp, tmp2)); | |
3955 | ||
3956 | if (! unordered) | |
32b5b1aa | 3957 | { |
e075ae69 RH |
3958 | /* We have two options here -- use sahf, or testing bits of ah |
3959 | directly. On PPRO, they are equivalent, sahf being one byte | |
3960 | smaller. On Pentium, sahf is non-pairable while test is UV | |
3961 | pairable. */ | |
3962 | ||
3963 | if (TARGET_USE_SAHF || optimize_size) | |
32b5b1aa | 3964 | { |
e075ae69 | 3965 | do_sahf: |
e9a25f70 | 3966 | |
e075ae69 RH |
3967 | /* The FP codes work out to act like unsigned. */ |
3968 | code = unsigned_comparison (code); | |
3969 | emit_insn (gen_x86_sahf_1 (tmp)); | |
3970 | intcmp_mode = CCmode; | |
32b5b1aa SC |
3971 | } |
3972 | else | |
3973 | { | |
e075ae69 RH |
3974 | /* |
3975 | * The numbers below correspond to the bits of the FPSW in AH. | |
3976 | * C3, C2, and C0 are in bits 0x40, 0x40, and 0x01 respectively. | |
3977 | * | |
3978 | * cmp C3 C2 C0 | |
3979 | * > 0 0 0 | |
3980 | * < 0 0 1 | |
3981 | * = 1 0 0 | |
3982 | * un 1 1 1 | |
3983 | */ | |
3984 | ||
3985 | int mask; | |
3986 | ||
3987 | switch (code) | |
32b5b1aa | 3988 | { |
e075ae69 RH |
3989 | case GT: |
3990 | mask = 0x01; | |
3991 | code = EQ; | |
3992 | break; | |
3993 | case LT: | |
3994 | mask = 0x01; | |
3995 | code = NE; | |
3996 | break; | |
3997 | case GE: | |
3998 | /* We'd have to use `xorb 1,ah; andb 0x41,ah', so it's | |
3999 | faster in all cases to just fall back on sahf. */ | |
4000 | goto do_sahf; | |
4001 | case LE: | |
4002 | mask = 0x41; | |
4003 | code = NE; | |
4004 | break; | |
4005 | case EQ: | |
4006 | mask = 0x40; | |
4007 | code = NE; | |
4008 | break; | |
4009 | case NE: | |
4010 | mask = 0x40; | |
4011 | code = EQ; | |
4012 | break; | |
4013 | default: | |
4014 | abort (); | |
32b5b1aa | 4015 | } |
e075ae69 RH |
4016 | |
4017 | emit_insn (gen_testqi_ext_0 (tmp, GEN_INT (mask))); | |
4018 | intcmp_mode = CCNOmode; | |
32b5b1aa SC |
4019 | } |
4020 | } | |
4021 | else | |
4022 | { | |
e075ae69 RH |
4023 | /* In the unordered case, we have to check C2 for NaN's, which |
4024 | doesn't happen to work out to anything nice combination-wise. | |
4025 | So do some bit twiddling on the value we've got in AH to come | |
4026 | up with an appropriate set of condition codes. */ | |
4027 | ||
4028 | intcmp_mode = CCNOmode; | |
4029 | switch (code) | |
32b5b1aa | 4030 | { |
e075ae69 RH |
4031 | case GT: |
4032 | emit_insn (gen_testqi_ext_0 (tmp, GEN_INT (0x45))); | |
4033 | code = EQ; | |
4034 | break; | |
4035 | case LT: | |
4036 | emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45))); | |
4037 | emit_insn (gen_cmpqi_ext_3 (tmp, GEN_INT (0x01))); | |
4038 | intcmp_mode = CCmode; | |
4039 | code = EQ; | |
4040 | break; | |
4041 | case GE: | |
4042 | emit_insn (gen_testqi_ext_0 (tmp, GEN_INT (0x05))); | |
4043 | code = EQ; | |
4044 | break; | |
4045 | case LE: | |
4046 | emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45))); | |
4047 | emit_insn (gen_addqi_ext_1 (tmp, tmp, constm1_rtx)); | |
4048 | emit_insn (gen_cmpqi_ext_3 (tmp, GEN_INT (0x40))); | |
4049 | intcmp_mode = CCmode; | |
4050 | code = LTU; | |
4051 | break; | |
4052 | case EQ: | |
4053 | emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45))); | |
4054 | emit_insn (gen_cmpqi_ext_3 (tmp, GEN_INT (0x40))); | |
4055 | intcmp_mode = CCmode; | |
4056 | code = EQ; | |
4057 | break; | |
4058 | case NE: | |
4059 | emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45))); | |
4060 | emit_insn (gen_xorcqi_ext_1 (tmp, tmp, GEN_INT (0x40))); | |
4061 | code = NE; | |
4062 | break; | |
4063 | default: | |
4064 | abort (); | |
32b5b1aa SC |
4065 | } |
4066 | } | |
32b5b1aa | 4067 | } |
e075ae69 RH |
4068 | |
4069 | /* Return the test that should be put into the flags user, i.e. | |
4070 | the bcc, scc, or cmov instruction. */ | |
4071 | return gen_rtx_fmt_ee (code, VOIDmode, | |
4072 | gen_rtx_REG (intcmp_mode, FLAGS_REG), | |
4073 | const0_rtx); | |
4074 | } | |
4075 | ||
4076 | static rtx | |
4077 | ix86_expand_compare (code, unordered) | |
4078 | enum rtx_code code; | |
4079 | int unordered; | |
4080 | { | |
4081 | rtx op0, op1, ret; | |
4082 | op0 = ix86_compare_op0; | |
4083 | op1 = ix86_compare_op1; | |
4084 | ||
4085 | if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT) | |
4086 | ret = ix86_expand_fp_compare (code, op0, op1, unordered); | |
32b5b1aa | 4087 | else |
e075ae69 RH |
4088 | ret = ix86_expand_int_compare (code, op0, op1); |
4089 | ||
4090 | return ret; | |
4091 | } | |
4092 | ||
4093 | void | |
4094 | ix86_expand_branch (code, unordered, label) | |
4095 | enum rtx_code code; | |
4096 | int unordered; | |
4097 | rtx label; | |
4098 | { | |
4099 | rtx tmp, lo[2], hi[2], label2; | |
4100 | enum rtx_code code1, code2, code3; | |
4101 | ||
4102 | if (GET_MODE (ix86_compare_op0) != DImode) | |
32b5b1aa | 4103 | { |
e075ae69 RH |
4104 | tmp = ix86_expand_compare (code, unordered); |
4105 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4106 | gen_rtx_LABEL_REF (VOIDmode, label), | |
4107 | pc_rtx); | |
4108 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
32b5b1aa SC |
4109 | return; |
4110 | } | |
32b5b1aa | 4111 | |
e075ae69 RH |
4112 | /* Expand DImode branch into multiple compare+branch. */ |
4113 | ||
4114 | if (CONSTANT_P (ix86_compare_op0) && ! CONSTANT_P (ix86_compare_op1)) | |
32b5b1aa | 4115 | { |
e075ae69 RH |
4116 | tmp = ix86_compare_op0; |
4117 | ix86_compare_op0 = ix86_compare_op1; | |
4118 | ix86_compare_op1 = tmp; | |
4119 | code = swap_condition (code); | |
4120 | } | |
4121 | split_di (&ix86_compare_op0, 1, lo+0, hi+0); | |
4122 | split_di (&ix86_compare_op1, 1, lo+1, hi+1); | |
32b5b1aa | 4123 | |
e075ae69 RH |
4124 | /* When comparing for equality, we can use (hi0^hi1)|(lo0^lo1) to avoid |
4125 | two branches. This costs one extra insn, so disable when optimizing | |
4126 | for size. */ | |
32b5b1aa | 4127 | |
e075ae69 RH |
4128 | if ((code == EQ || code == NE) |
4129 | && (!optimize_size | |
4130 | || hi[1] == const0_rtx || lo[1] == const0_rtx)) | |
4131 | { | |
4132 | rtx xor0, xor1; | |
32b5b1aa | 4133 | |
e075ae69 RH |
4134 | xor1 = hi[0]; |
4135 | if (hi[1] != const0_rtx) | |
4136 | { | |
4137 | xor1 = expand_binop (SImode, xor_optab, xor1, hi[1], | |
4138 | NULL_RTX, 0, OPTAB_WIDEN); | |
4139 | } | |
32b5b1aa | 4140 | |
e075ae69 RH |
4141 | xor0 = lo[0]; |
4142 | if (lo[1] != const0_rtx) | |
4143 | { | |
4144 | xor0 = expand_binop (SImode, xor_optab, xor0, lo[1], | |
4145 | NULL_RTX, 0, OPTAB_WIDEN); | |
32b5b1aa SC |
4146 | } |
4147 | ||
e075ae69 RH |
4148 | tmp = expand_binop (SImode, ior_optab, xor1, xor0, |
4149 | NULL_RTX, 0, OPTAB_WIDEN); | |
32b5b1aa | 4150 | |
e075ae69 RH |
4151 | ix86_compare_op0 = tmp; |
4152 | ix86_compare_op1 = const0_rtx; | |
4153 | ix86_expand_branch (code, unordered, label); | |
4154 | return; | |
32b5b1aa SC |
4155 | } |
4156 | ||
e075ae69 RH |
4157 | /* Otherwise, if we are doing less-than, op1 is a constant and the |
4158 | low word is zero, then we can just examine the high word. */ | |
4159 | ||
4160 | if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx | |
4161 | && (code == LT || code == LTU)) | |
32b5b1aa | 4162 | { |
e075ae69 RH |
4163 | ix86_compare_op0 = hi[0]; |
4164 | ix86_compare_op1 = hi[1]; | |
4165 | ix86_expand_branch (code, unordered, label); | |
4166 | return; | |
4167 | } | |
32b5b1aa | 4168 | |
e075ae69 RH |
4169 | /* Otherwise, we need two or three jumps. */ |
4170 | ||
4171 | label2 = gen_label_rtx (); | |
32b5b1aa | 4172 | |
e075ae69 RH |
4173 | code1 = code; |
4174 | code2 = swap_condition (code); | |
4175 | code3 = unsigned_condition (code); | |
4176 | ||
4177 | switch (code) | |
4178 | { | |
4179 | case LT: case GT: case LTU: case GTU: | |
4180 | break; | |
4181 | ||
4182 | case LE: code1 = LT; code2 = GT; break; | |
4183 | case GE: code1 = GT; code2 = LT; break; | |
4184 | case LEU: code1 = LTU; code2 = GTU; break; | |
4185 | case GEU: code1 = GTU; code2 = LTU; break; | |
4186 | ||
4187 | case EQ: code1 = NIL; code2 = NE; break; | |
4188 | case NE: code2 = NIL; break; | |
4189 | ||
4190 | default: | |
4191 | abort (); | |
32b5b1aa | 4192 | } |
e075ae69 RH |
4193 | |
4194 | /* | |
4195 | * a < b => | |
4196 | * if (hi(a) < hi(b)) goto true; | |
4197 | * if (hi(a) > hi(b)) goto false; | |
4198 | * if (lo(a) < lo(b)) goto true; | |
4199 | * false: | |
4200 | */ | |
4201 | ||
4202 | ix86_compare_op0 = hi[0]; | |
4203 | ix86_compare_op1 = hi[1]; | |
4204 | ||
4205 | if (code1 != NIL) | |
4206 | ix86_expand_branch (code1, unordered, label); | |
4207 | if (code2 != NIL) | |
4208 | ix86_expand_branch (code2, unordered, label2); | |
4209 | ||
4210 | ix86_compare_op0 = lo[0]; | |
4211 | ix86_compare_op1 = lo[1]; | |
4212 | ix86_expand_branch (code3, unordered, label); | |
4213 | ||
4214 | if (code2 != NIL) | |
4215 | emit_label (label2); | |
32b5b1aa | 4216 | } |
e075ae69 | 4217 | |
32b5b1aa | 4218 | int |
e075ae69 RH |
4219 | ix86_expand_setcc (code, unordered, dest) |
4220 | enum rtx_code code; | |
4221 | int unordered; | |
4222 | rtx dest; | |
32b5b1aa | 4223 | { |
e075ae69 RH |
4224 | rtx ret, tmp; |
4225 | int type; | |
4226 | ||
4227 | if (GET_MODE (ix86_compare_op0) == DImode) | |
4228 | return 0; /* FAIL */ | |
4229 | ||
4230 | /* Three modes of generation: | |
4231 | 0 -- destination does not overlap compare sources: | |
4232 | clear dest first, emit strict_low_part setcc. | |
4233 | 1 -- destination does overlap compare sources: | |
4234 | emit subreg setcc, zero extend. | |
4235 | 2 -- destination is in QImode: | |
4236 | emit setcc only. | |
4237 | */ | |
4238 | ||
4239 | type = 0; | |
4240 | /* %%% reload problems with in-out. Revisit. */ | |
4241 | type = 1; | |
4242 | ||
4243 | if (GET_MODE (dest) == QImode) | |
4244 | type = 2; | |
4245 | else if (reg_overlap_mentioned_p (dest, ix86_compare_op0) | |
4246 | || reg_overlap_mentioned_p (dest, ix86_compare_op0)) | |
4247 | type = 1; | |
4248 | ||
4249 | if (type == 0) | |
4250 | emit_move_insn (dest, const0_rtx); | |
4251 | ||
4252 | ret = ix86_expand_compare (code, unordered); | |
4253 | PUT_MODE (ret, QImode); | |
4254 | ||
4255 | tmp = dest; | |
4256 | if (type == 0) | |
32b5b1aa | 4257 | { |
e075ae69 RH |
4258 | tmp = gen_lowpart (QImode, dest); |
4259 | tmp = gen_rtx_STRICT_LOW_PART (VOIDmode, tmp); | |
4260 | } | |
4261 | else if (type == 1) | |
4262 | { | |
4263 | if (!cse_not_expected) | |
4264 | tmp = gen_reg_rtx (QImode); | |
4265 | else | |
4266 | tmp = gen_lowpart (QImode, dest); | |
4267 | } | |
32b5b1aa | 4268 | |
e075ae69 RH |
4269 | emit_insn (gen_rtx_SET (VOIDmode, tmp, ret)); |
4270 | ||
4271 | if (type == 1) | |
4272 | { | |
4273 | rtx clob; | |
4274 | ||
4275 | tmp = gen_rtx_ZERO_EXTEND (GET_MODE (dest), tmp); | |
4276 | tmp = gen_rtx_SET (VOIDmode, dest, tmp); | |
4277 | clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); | |
4278 | tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob)); | |
4279 | emit_insn (tmp); | |
32b5b1aa | 4280 | } |
e075ae69 RH |
4281 | |
4282 | return 1; /* DONE */ | |
32b5b1aa | 4283 | } |
e075ae69 | 4284 | |
32b5b1aa | 4285 | int |
e075ae69 RH |
4286 | ix86_expand_int_movcc (operands) |
4287 | rtx operands[]; | |
32b5b1aa | 4288 | { |
e075ae69 RH |
4289 | enum rtx_code code = GET_CODE (operands[1]), compare_code; |
4290 | rtx compare_seq, compare_op; | |
32b5b1aa | 4291 | |
e075ae69 RH |
4292 | start_sequence (); |
4293 | compare_op = ix86_expand_compare (code, code == EQ || code == NE); | |
4294 | compare_seq = gen_sequence (); | |
4295 | end_sequence (); | |
4296 | ||
4297 | compare_code = GET_CODE (compare_op); | |
4298 | ||
4299 | /* Don't attempt mode expansion here -- if we had to expand 5 or 6 | |
4300 | HImode insns, we'd be swallowed in word prefix ops. */ | |
4301 | ||
4302 | if (GET_MODE (operands[0]) != HImode | |
4303 | && GET_CODE (operands[2]) == CONST_INT | |
4304 | && GET_CODE (operands[3]) == CONST_INT) | |
4305 | { | |
4306 | rtx out = operands[0]; | |
4307 | HOST_WIDE_INT ct = INTVAL (operands[2]); | |
4308 | HOST_WIDE_INT cf = INTVAL (operands[3]); | |
4309 | HOST_WIDE_INT diff; | |
4310 | ||
4311 | /* Special cases: */ | |
4312 | if (ct == 0) | |
4313 | { | |
4314 | ct = cf; | |
4315 | cf = 0; | |
4316 | compare_code = reverse_condition (compare_code); | |
4317 | code = reverse_condition (code); | |
4318 | } | |
4319 | if (cf == 0 && ct == -1 && (compare_code == LTU || compare_code == GEU)) | |
4320 | { | |
4321 | /* | |
4322 | * xorl dest,dest | |
4323 | * cmpl op0,op1 | |
4324 | * sbbl dest,dest | |
4325 | * | |
4326 | * Size 6. | |
4327 | */ | |
4328 | ||
4329 | /* Detect overlap between destination and compare sources. */ | |
4330 | rtx tmp = out; | |
4331 | ||
4332 | if (reg_overlap_mentioned_p (out, ix86_compare_op0) | |
4333 | || reg_overlap_mentioned_p (out, ix86_compare_op0)) | |
4334 | tmp = gen_reg_rtx (SImode); | |
4335 | ||
4336 | emit_insn (compare_seq); | |
4337 | emit_insn (gen_x86_movsicc_0_m1 (tmp)); | |
4338 | ||
4339 | if (compare_code == GEU) | |
4340 | emit_insn (gen_one_cmplsi2 (tmp, tmp)); | |
4341 | ||
4342 | if (tmp != out) | |
4343 | emit_move_insn (out, tmp); | |
4344 | ||
4345 | return 1; /* DONE */ | |
4346 | } | |
4347 | ||
4348 | diff = ct - cf; | |
4349 | if (diff < 0) | |
4350 | { | |
4351 | HOST_WIDE_INT tmp; | |
4352 | tmp = ct, ct = cf, cf = tmp; | |
4353 | diff = -diff; | |
4354 | compare_code = reverse_condition (compare_code); | |
4355 | code = reverse_condition (code); | |
4356 | } | |
4357 | if (diff == 1 || diff == 2 || diff == 4 || diff == 8 | |
4358 | || diff == 3 || diff == 5 || diff == 9) | |
4359 | { | |
4360 | /* | |
4361 | * xorl dest,dest | |
4362 | * cmpl op1,op2 | |
4363 | * setcc dest | |
4364 | * lea cf(dest*(ct-cf)),dest | |
4365 | * | |
4366 | * Size 14. | |
4367 | * | |
4368 | * This also catches the degenerate setcc-only case. | |
4369 | */ | |
4370 | ||
4371 | rtx tmp; | |
4372 | int nops; | |
4373 | ||
4374 | out = emit_store_flag (out, code, ix86_compare_op0, | |
4375 | ix86_compare_op1, VOIDmode, 0, 1); | |
4376 | ||
4377 | nops = 0; | |
4378 | if (diff == 1) | |
4379 | tmp = out; | |
4380 | else | |
4381 | { | |
4382 | tmp = gen_rtx_MULT (SImode, out, GEN_INT (diff & ~1)); | |
4383 | nops++; | |
4384 | if (diff & 1) | |
4385 | { | |
4386 | tmp = gen_rtx_PLUS (SImode, tmp, out); | |
4387 | nops++; | |
4388 | } | |
4389 | } | |
4390 | if (cf != 0) | |
4391 | { | |
4392 | tmp = gen_rtx_PLUS (SImode, tmp, GEN_INT (cf)); | |
4393 | nops++; | |
4394 | } | |
4395 | if (tmp != out) | |
4396 | { | |
4397 | if (nops == 0) | |
4398 | emit_move_insn (out, tmp); | |
4399 | else if (nops == 1) | |
4400 | { | |
4401 | rtx clob; | |
4402 | ||
4403 | clob = gen_rtx_REG (CCmode, FLAGS_REG); | |
4404 | clob = gen_rtx_CLOBBER (VOIDmode, clob); | |
4405 | ||
4406 | tmp = gen_rtx_SET (VOIDmode, out, tmp); | |
4407 | tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob)); | |
4408 | emit_insn (tmp); | |
4409 | } | |
4410 | else | |
4411 | emit_insn (gen_rtx_SET (VOIDmode, out, tmp)); | |
4412 | } | |
4413 | if (out != operands[0]) | |
4414 | emit_move_insn (operands[0], out); | |
4415 | ||
4416 | return 1; /* DONE */ | |
4417 | } | |
4418 | ||
4419 | /* | |
4420 | * General case: Jumpful: | |
4421 | * xorl dest,dest cmpl op1, op2 | |
4422 | * cmpl op1, op2 movl ct, dest | |
4423 | * setcc dest jcc 1f | |
4424 | * decl dest movl cf, dest | |
4425 | * andl (cf-ct),dest 1: | |
4426 | * addl ct,dest | |
4427 | * | |
4428 | * Size 20. Size 14. | |
4429 | * | |
4430 | * This is reasonably steep, but branch mispredict costs are | |
4431 | * high on modern cpus, so consider failing only if optimizing | |
4432 | * for space. | |
4433 | * | |
4434 | * %%% Parameterize branch_cost on the tuning architecture, then | |
4435 | * use that. The 80386 couldn't care less about mispredicts. | |
4436 | */ | |
4437 | ||
4438 | if (!optimize_size && !TARGET_CMOVE) | |
4439 | { | |
4440 | if (ct == 0) | |
4441 | { | |
4442 | ct = cf; | |
4443 | cf = 0; | |
4444 | compare_code = reverse_condition (compare_code); | |
4445 | code = reverse_condition (code); | |
4446 | } | |
4447 | ||
4448 | out = emit_store_flag (out, code, ix86_compare_op0, | |
4449 | ix86_compare_op1, VOIDmode, 0, 1); | |
4450 | ||
4451 | emit_insn (gen_addsi3 (out, out, constm1_rtx)); | |
4452 | emit_insn (gen_andsi3 (out, out, GEN_INT (cf-ct))); | |
4453 | if (ct != 0) | |
4454 | emit_insn (gen_addsi3 (out, out, GEN_INT (ct))); | |
4455 | if (out != operands[0]) | |
4456 | emit_move_insn (operands[0], out); | |
4457 | ||
4458 | return 1; /* DONE */ | |
4459 | } | |
4460 | } | |
4461 | ||
4462 | if (!TARGET_CMOVE) | |
4463 | { | |
4464 | /* Try a few things more with specific constants and a variable. */ | |
4465 | ||
4466 | optab op = NULL; | |
4467 | rtx var, orig_out, out, tmp; | |
4468 | ||
4469 | if (optimize_size) | |
4470 | return 0; /* FAIL */ | |
4471 | ||
4472 | /* If one of the two operands is an interesting constant, load a | |
4473 | constant with the above and mask it in with a logical operation. */ | |
4474 | ||
4475 | if (GET_CODE (operands[2]) == CONST_INT) | |
4476 | { | |
4477 | var = operands[3]; | |
4478 | if (INTVAL (operands[2]) == 0) | |
4479 | operands[3] = constm1_rtx, op = and_optab; | |
4480 | else if (INTVAL (operands[2]) == -1) | |
4481 | operands[3] = const0_rtx, op = ior_optab; | |
4482 | } | |
4483 | else if (GET_CODE (operands[3]) == CONST_INT) | |
4484 | { | |
4485 | var = operands[2]; | |
4486 | if (INTVAL (operands[3]) == 0) | |
4487 | operands[2] = constm1_rtx, op = and_optab; | |
4488 | else if (INTVAL (operands[3]) == -1) | |
4489 | operands[2] = const0_rtx, op = ior_optab; | |
4490 | } | |
4491 | ||
4492 | if (op == NULL) | |
4493 | return 0; /* FAIL */ | |
4494 | ||
4495 | orig_out = operands[0]; | |
4496 | tmp = gen_reg_rtx (GET_MODE (orig_out)); | |
4497 | operands[0] = tmp; | |
4498 | ||
4499 | /* Recurse to get the constant loaded. */ | |
4500 | if (ix86_expand_int_movcc (operands) == 0) | |
4501 | return 0; /* FAIL */ | |
4502 | ||
4503 | /* Mask in the interesting variable. */ | |
4504 | out = expand_binop (GET_MODE (orig_out), op, var, tmp, orig_out, 0, | |
4505 | OPTAB_WIDEN); | |
4506 | if (out != orig_out) | |
4507 | emit_move_insn (orig_out, out); | |
4508 | ||
4509 | return 1; /* DONE */ | |
4510 | } | |
4511 | ||
4512 | /* | |
4513 | * For comparison with above, | |
4514 | * | |
4515 | * movl cf,dest | |
4516 | * movl ct,tmp | |
4517 | * cmpl op1,op2 | |
4518 | * cmovcc tmp,dest | |
4519 | * | |
4520 | * Size 15. | |
4521 | */ | |
4522 | ||
4523 | if (! nonimmediate_operand (operands[2], GET_MODE (operands[0]))) | |
4524 | operands[2] = force_reg (GET_MODE (operands[0]), operands[2]); | |
4525 | if (! nonimmediate_operand (operands[3], GET_MODE (operands[0]))) | |
4526 | operands[3] = force_reg (GET_MODE (operands[0]), operands[3]); | |
4527 | ||
4528 | emit_insn (compare_seq); | |
4529 | emit_insn (gen_rtx_SET (VOIDmode, operands[0], | |
4530 | gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), | |
4531 | compare_op, operands[2], | |
4532 | operands[3]))); | |
4533 | ||
4534 | return 1; /* DONE */ | |
e9a25f70 | 4535 | } |
e075ae69 | 4536 | |
32b5b1aa | 4537 | int |
e075ae69 RH |
4538 | ix86_expand_fp_movcc (operands) |
4539 | rtx operands[]; | |
32b5b1aa | 4540 | { |
e075ae69 RH |
4541 | enum rtx_code code; |
4542 | enum machine_mode mode; | |
4543 | rtx tmp; | |
32b5b1aa | 4544 | |
e075ae69 RH |
4545 | /* The floating point conditional move instructions don't directly |
4546 | support conditions resulting from a signed integer comparison. */ | |
32b5b1aa | 4547 | |
e075ae69 RH |
4548 | code = GET_CODE (operands[1]); |
4549 | switch (code) | |
4550 | { | |
4551 | case LT: | |
4552 | case LE: | |
4553 | case GE: | |
4554 | case GT: | |
4555 | tmp = gen_reg_rtx (QImode); | |
4556 | ix86_expand_setcc (code, 0, tmp); | |
4557 | code = NE; | |
4558 | ix86_compare_op0 = tmp; | |
4559 | ix86_compare_op1 = const0_rtx; | |
4560 | break; | |
4561 | ||
4562 | default: | |
4563 | break; | |
4564 | } | |
e9a25f70 | 4565 | |
e075ae69 RH |
4566 | mode = SELECT_CC_MODE (code, ix86_compare_op0, ix86_compare_op1); |
4567 | emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, FLAGS_REG), | |
4568 | gen_rtx_COMPARE (mode, | |
4569 | ix86_compare_op0, | |
4570 | ix86_compare_op1))); | |
4571 | emit_insn (gen_rtx_SET (VOIDmode, operands[0], | |
4572 | gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]), | |
4573 | gen_rtx_fmt_ee (code, VOIDmode, | |
4574 | gen_rtx_REG (mode, FLAGS_REG), | |
4575 | const0_rtx), | |
4576 | operands[2], | |
4577 | operands[3]))); | |
32b5b1aa | 4578 | |
e075ae69 | 4579 | return 1; |
32b5b1aa SC |
4580 | } |
4581 | ||
32b5b1aa | 4582 | int |
e075ae69 RH |
4583 | ix86_split_movdi (operands) |
4584 | rtx operands[]; | |
32b5b1aa | 4585 | { |
e075ae69 RH |
4586 | split_di (operands+0, 1, operands+2, operands+3); |
4587 | split_di (operands+1, 1, operands+4, operands+5); | |
4588 | if (reg_overlap_mentioned_p (operands[2], operands[1])) | |
4589 | { | |
4590 | rtx tmp; | |
4591 | if (!reg_overlap_mentioned_p (operands[3], operands[4])) | |
4592 | { | |
4593 | tmp = operands[2], operands[2] = operands[3], operands[3] = tmp; | |
4594 | tmp = operands[4], operands[4] = operands[5], operands[5] = tmp; | |
4595 | } | |
4596 | else | |
4597 | { | |
4598 | emit_insn (gen_push (operands[4])); | |
4599 | emit_insn (gen_rtx_SET (VOIDmode, operands[3], operands[5])); | |
4600 | emit_insn (gen_popsi1 (operands[2])); | |
4601 | ||
4602 | return 1; /* DONE */ | |
4603 | } | |
4604 | } | |
32b5b1aa | 4605 | |
e9a25f70 | 4606 | return 0; |
32b5b1aa | 4607 | } |
32b5b1aa | 4608 | |
e075ae69 RH |
4609 | void |
4610 | ix86_split_ashldi (operands, scratch) | |
4611 | rtx *operands, scratch; | |
32b5b1aa | 4612 | { |
e075ae69 RH |
4613 | rtx low[2], high[2]; |
4614 | int count; | |
b985a30f | 4615 | |
e075ae69 RH |
4616 | if (GET_CODE (operands[2]) == CONST_INT) |
4617 | { | |
4618 | split_di (operands, 2, low, high); | |
4619 | count = INTVAL (operands[2]) & 63; | |
32b5b1aa | 4620 | |
e075ae69 RH |
4621 | if (count >= 32) |
4622 | { | |
4623 | emit_move_insn (high[0], low[1]); | |
4624 | emit_move_insn (low[0], const0_rtx); | |
b985a30f | 4625 | |
e075ae69 RH |
4626 | if (count > 32) |
4627 | emit_insn (gen_ashlsi3 (high[0], high[0], GEN_INT (count - 32))); | |
4628 | } | |
4629 | else | |
4630 | { | |
4631 | if (!rtx_equal_p (operands[0], operands[1])) | |
4632 | emit_move_insn (operands[0], operands[1]); | |
4633 | emit_insn (gen_x86_shld_1 (high[0], low[0], GEN_INT (count))); | |
4634 | emit_insn (gen_ashlsi3 (low[0], low[0], GEN_INT (count))); | |
4635 | } | |
4636 | } | |
4637 | else | |
4638 | { | |
4639 | if (!rtx_equal_p (operands[0], operands[1])) | |
4640 | emit_move_insn (operands[0], operands[1]); | |
b985a30f | 4641 | |
e075ae69 | 4642 | split_di (operands, 1, low, high); |
b985a30f | 4643 | |
e075ae69 RH |
4644 | emit_insn (gen_x86_shld_1 (high[0], low[0], operands[2])); |
4645 | emit_insn (gen_ashlsi3 (low[0], low[0], operands[2])); | |
32b5b1aa | 4646 | |
e075ae69 RH |
4647 | if (TARGET_CMOVE && (! reload_completed || scratch)) |
4648 | { | |
4649 | if (! reload_completed) | |
4650 | scratch = force_reg (SImode, const0_rtx); | |
4651 | else | |
4652 | emit_move_insn (scratch, const0_rtx); | |
4653 | ||
4654 | emit_insn (gen_x86_shift_adj_1 (high[0], low[0], operands[2], | |
4655 | scratch)); | |
4656 | } | |
4657 | else | |
4658 | emit_insn (gen_x86_shift_adj_2 (high[0], low[0], operands[2])); | |
4659 | } | |
e9a25f70 | 4660 | } |
32b5b1aa | 4661 | |
e075ae69 RH |
4662 | void |
4663 | ix86_split_ashrdi (operands, scratch) | |
4664 | rtx *operands, scratch; | |
32b5b1aa | 4665 | { |
e075ae69 RH |
4666 | rtx low[2], high[2]; |
4667 | int count; | |
32b5b1aa | 4668 | |
e075ae69 RH |
4669 | if (GET_CODE (operands[2]) == CONST_INT) |
4670 | { | |
4671 | split_di (operands, 2, low, high); | |
4672 | count = INTVAL (operands[2]) & 63; | |
32b5b1aa | 4673 | |
e075ae69 RH |
4674 | if (count >= 32) |
4675 | { | |
4676 | emit_move_insn (low[0], high[1]); | |
32b5b1aa | 4677 | |
e075ae69 RH |
4678 | if (! reload_completed) |
4679 | emit_insn (gen_ashrsi3 (high[0], low[0], GEN_INT (31))); | |
4680 | else | |
4681 | { | |
4682 | emit_move_insn (high[0], low[0]); | |
4683 | emit_insn (gen_ashrsi3 (high[0], high[0], GEN_INT (31))); | |
4684 | } | |
4685 | ||
4686 | if (count > 32) | |
4687 | emit_insn (gen_ashrsi3 (low[0], low[0], GEN_INT (count - 32))); | |
4688 | } | |
4689 | else | |
4690 | { | |
4691 | if (!rtx_equal_p (operands[0], operands[1])) | |
4692 | emit_move_insn (operands[0], operands[1]); | |
4693 | emit_insn (gen_x86_shrd_1 (low[0], high[0], GEN_INT (count))); | |
4694 | emit_insn (gen_ashrsi3 (high[0], high[0], GEN_INT (count))); | |
4695 | } | |
4696 | } | |
4697 | else | |
32b5b1aa | 4698 | { |
e075ae69 RH |
4699 | if (!rtx_equal_p (operands[0], operands[1])) |
4700 | emit_move_insn (operands[0], operands[1]); | |
4701 | ||
4702 | split_di (operands, 1, low, high); | |
4703 | ||
4704 | emit_insn (gen_x86_shrd_1 (low[0], high[0], operands[2])); | |
4705 | emit_insn (gen_ashrsi3 (high[0], high[0], operands[2])); | |
4706 | ||
4707 | if (TARGET_CMOVE && (!reload_completed || scratch)) | |
4708 | { | |
4709 | if (! reload_completed) | |
4710 | scratch = gen_reg_rtx (SImode); | |
4711 | emit_move_insn (scratch, high[0]); | |
4712 | emit_insn (gen_ashrsi3 (scratch, scratch, GEN_INT (31))); | |
4713 | emit_insn (gen_x86_shift_adj_1 (low[0], high[0], operands[2], | |
4714 | scratch)); | |
4715 | } | |
4716 | else | |
4717 | emit_insn (gen_x86_shift_adj_3 (low[0], high[0], operands[2])); | |
32b5b1aa | 4718 | } |
e075ae69 | 4719 | } |
32b5b1aa | 4720 | |
e075ae69 RH |
4721 | void |
4722 | ix86_split_lshrdi (operands, scratch) | |
4723 | rtx *operands, scratch; | |
4724 | { | |
4725 | rtx low[2], high[2]; | |
4726 | int count; | |
32b5b1aa | 4727 | |
e075ae69 | 4728 | if (GET_CODE (operands[2]) == CONST_INT) |
32b5b1aa | 4729 | { |
e075ae69 RH |
4730 | split_di (operands, 2, low, high); |
4731 | count = INTVAL (operands[2]) & 63; | |
4732 | ||
4733 | if (count >= 32) | |
c7271385 | 4734 | { |
e075ae69 RH |
4735 | emit_move_insn (low[0], high[1]); |
4736 | emit_move_insn (high[0], const0_rtx); | |
32b5b1aa | 4737 | |
e075ae69 RH |
4738 | if (count > 32) |
4739 | emit_insn (gen_lshrsi3 (low[0], low[0], GEN_INT (count - 32))); | |
4740 | } | |
4741 | else | |
4742 | { | |
4743 | if (!rtx_equal_p (operands[0], operands[1])) | |
4744 | emit_move_insn (operands[0], operands[1]); | |
4745 | emit_insn (gen_x86_shrd_1 (low[0], high[0], GEN_INT (count))); | |
4746 | emit_insn (gen_lshrsi3 (high[0], high[0], GEN_INT (count))); | |
4747 | } | |
32b5b1aa | 4748 | } |
e075ae69 RH |
4749 | else |
4750 | { | |
4751 | if (!rtx_equal_p (operands[0], operands[1])) | |
4752 | emit_move_insn (operands[0], operands[1]); | |
32b5b1aa | 4753 | |
e075ae69 RH |
4754 | split_di (operands, 1, low, high); |
4755 | ||
4756 | emit_insn (gen_x86_shrd_1 (low[0], high[0], operands[2])); | |
4757 | emit_insn (gen_lshrsi3 (high[0], high[0], operands[2])); | |
4758 | ||
4759 | /* Heh. By reversing the arguments, we can reuse this pattern. */ | |
4760 | if (TARGET_CMOVE && (! reload_completed || scratch)) | |
4761 | { | |
4762 | if (! reload_completed) | |
4763 | scratch = force_reg (SImode, const0_rtx); | |
4764 | else | |
4765 | emit_move_insn (scratch, const0_rtx); | |
4766 | ||
4767 | emit_insn (gen_x86_shift_adj_1 (low[0], high[0], operands[2], | |
4768 | scratch)); | |
4769 | } | |
4770 | else | |
4771 | emit_insn (gen_x86_shift_adj_2 (low[0], high[0], operands[2])); | |
4772 | } | |
32b5b1aa | 4773 | } |
3f803cd9 | 4774 | |
e075ae69 RH |
4775 | /* Expand the appropriate insns for doing strlen if not just doing |
4776 | repnz; scasb | |
4777 | ||
4778 | out = result, initialized with the start address | |
4779 | align_rtx = alignment of the address. | |
4780 | scratch = scratch register, initialized with the startaddress when | |
4781 | not aligned, otherwise undefined | |
3f803cd9 SC |
4782 | |
4783 | This is just the body. It needs the initialisations mentioned above and | |
4784 | some address computing at the end. These things are done in i386.md. */ | |
4785 | ||
e075ae69 RH |
4786 | void |
4787 | ix86_expand_strlensi_unroll_1 (out, align_rtx, scratch) | |
4788 | rtx out, align_rtx, scratch; | |
3f803cd9 | 4789 | { |
e075ae69 RH |
4790 | int align; |
4791 | rtx tmp; | |
4792 | rtx align_2_label = NULL_RTX; | |
4793 | rtx align_3_label = NULL_RTX; | |
4794 | rtx align_4_label = gen_label_rtx (); | |
4795 | rtx end_0_label = gen_label_rtx (); | |
4796 | rtx end_2_label = gen_label_rtx (); | |
4797 | rtx end_3_label = gen_label_rtx (); | |
4798 | rtx mem; | |
4799 | rtx flags = gen_rtx_REG (CCNOmode, FLAGS_REG); | |
4800 | ||
4801 | align = 0; | |
4802 | if (GET_CODE (align_rtx) == CONST_INT) | |
4803 | align = INTVAL (align_rtx); | |
3f803cd9 | 4804 | |
e9a25f70 | 4805 | /* Loop to check 1..3 bytes for null to get an aligned pointer. */ |
3f803cd9 | 4806 | |
e9a25f70 | 4807 | /* Is there a known alignment and is it less than 4? */ |
e075ae69 | 4808 | if (align < 4) |
3f803cd9 | 4809 | { |
e9a25f70 | 4810 | /* Is there a known alignment and is it not 2? */ |
e075ae69 | 4811 | if (align != 2) |
3f803cd9 | 4812 | { |
e075ae69 RH |
4813 | align_3_label = gen_label_rtx (); /* Label when aligned to 3-byte */ |
4814 | align_2_label = gen_label_rtx (); /* Label when aligned to 2-byte */ | |
4815 | ||
4816 | /* Leave just the 3 lower bits. */ | |
4817 | align_rtx = expand_binop (SImode, and_optab, scratch, GEN_INT (3), | |
4818 | NULL_RTX, 0, OPTAB_WIDEN); | |
4819 | ||
4820 | emit_insn (gen_cmpsi_0 (align_rtx, const0_rtx)); | |
4821 | ||
4822 | tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx); | |
4823 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4824 | gen_rtx_LABEL_REF (VOIDmode, | |
4825 | align_4_label), | |
4826 | pc_rtx); | |
4827 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
4828 | ||
4829 | emit_insn (gen_cmpsi_1 (align_rtx, GEN_INT (2))); | |
4830 | ||
4831 | tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx); | |
4832 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4833 | gen_rtx_LABEL_REF (VOIDmode, | |
4834 | align_2_label), | |
4835 | pc_rtx); | |
4836 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
4837 | ||
4838 | tmp = gen_rtx_GTU (VOIDmode, flags, const0_rtx); | |
4839 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4840 | gen_rtx_LABEL_REF (VOIDmode, | |
4841 | align_3_label), | |
4842 | pc_rtx); | |
4843 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
3f803cd9 SC |
4844 | } |
4845 | else | |
4846 | { | |
e9a25f70 JL |
4847 | /* Since the alignment is 2, we have to check 2 or 0 bytes; |
4848 | check if is aligned to 4 - byte. */ | |
e9a25f70 | 4849 | |
e075ae69 RH |
4850 | align_rtx = expand_binop (SImode, and_optab, scratch, GEN_INT (2), |
4851 | NULL_RTX, 0, OPTAB_WIDEN); | |
4852 | ||
4853 | emit_insn (gen_cmpsi_0 (align_rtx, const0_rtx)); | |
4854 | ||
4855 | tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx); | |
4856 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4857 | gen_rtx_LABEL_REF (VOIDmode, | |
4858 | align_4_label), | |
4859 | pc_rtx); | |
4860 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
3f803cd9 SC |
4861 | } |
4862 | ||
e075ae69 | 4863 | mem = gen_rtx_MEM (QImode, out); |
e9a25f70 | 4864 | |
e075ae69 | 4865 | /* Now compare the bytes. */ |
e9a25f70 | 4866 | |
e075ae69 RH |
4867 | /* Compare the first n unaligned byte on a byte per byte basis. */ |
4868 | emit_insn (gen_cmpqi_0 (mem, const0_rtx)); | |
e9a25f70 | 4869 | |
e075ae69 RH |
4870 | tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx); |
4871 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4872 | gen_rtx_LABEL_REF (VOIDmode, end_0_label), | |
4873 | pc_rtx); | |
4874 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
3f803cd9 | 4875 | |
e075ae69 RH |
4876 | /* Increment the address. */ |
4877 | emit_insn (gen_addsi3 (out, out, const1_rtx)); | |
e9a25f70 | 4878 | |
e075ae69 RH |
4879 | /* Not needed with an alignment of 2 */ |
4880 | if (align != 2) | |
4881 | { | |
4882 | emit_label (align_2_label); | |
3f803cd9 | 4883 | |
e075ae69 | 4884 | emit_insn (gen_cmpqi_0 (mem, const0_rtx)); |
3f803cd9 | 4885 | |
e075ae69 RH |
4886 | tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx); |
4887 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4888 | gen_rtx_LABEL_REF (VOIDmode, | |
4889 | end_0_label), | |
4890 | pc_rtx); | |
4891 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
4892 | ||
4893 | emit_insn (gen_addsi3 (out, out, const1_rtx)); | |
4894 | ||
4895 | emit_label (align_3_label); | |
4896 | } | |
4897 | ||
4898 | emit_insn (gen_cmpqi_0 (mem, const0_rtx)); | |
e9a25f70 | 4899 | |
e075ae69 RH |
4900 | tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx); |
4901 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4902 | gen_rtx_LABEL_REF (VOIDmode, end_0_label), | |
4903 | pc_rtx); | |
4904 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
4905 | ||
4906 | emit_insn (gen_addsi3 (out, out, const1_rtx)); | |
3f803cd9 SC |
4907 | } |
4908 | ||
e075ae69 RH |
4909 | /* Generate loop to check 4 bytes at a time. It is not a good idea to |
4910 | align this loop. It gives only huge programs, but does not help to | |
4911 | speed up. */ | |
4912 | emit_label (align_4_label); | |
3f803cd9 | 4913 | |
e075ae69 RH |
4914 | mem = gen_rtx_MEM (SImode, out); |
4915 | emit_move_insn (scratch, mem); | |
3f803cd9 | 4916 | |
e075ae69 RH |
4917 | /* Check first byte. */ |
4918 | emit_insn (gen_cmpqi_0 (gen_lowpart (QImode, scratch), const0_rtx)); | |
4919 | tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx); | |
4920 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4921 | gen_rtx_LABEL_REF (VOIDmode, end_0_label), | |
4922 | pc_rtx); | |
4923 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
4924 | ||
4925 | /* Check second byte. */ | |
4926 | emit_insn (gen_cmpqi_ext_3 (scratch, const0_rtx)); | |
4927 | tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx); | |
4928 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4929 | gen_rtx_LABEL_REF (VOIDmode, end_3_label), | |
4930 | pc_rtx); | |
4931 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
4932 | ||
4933 | /* Check third byte. */ | |
4934 | emit_insn (gen_testsi_1 (scratch, GEN_INT (0x00ff0000))); | |
4935 | tmp = gen_rtx_EQ (VOIDmode, flags, const0_rtx); | |
4936 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4937 | gen_rtx_LABEL_REF (VOIDmode, end_2_label), | |
4938 | pc_rtx); | |
4939 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
4940 | ||
4941 | /* Check fourth byte and increment address. */ | |
4942 | emit_insn (gen_addsi3 (out, out, GEN_INT (4))); | |
4943 | emit_insn (gen_testsi_1 (scratch, GEN_INT (0xff000000))); | |
4944 | tmp = gen_rtx_NE (VOIDmode, flags, const0_rtx); | |
4945 | tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, | |
4946 | gen_rtx_LABEL_REF (VOIDmode, align_4_label), | |
4947 | pc_rtx); | |
4948 | emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); | |
4949 | ||
4950 | /* Now generate fixups when the compare stops within a 4-byte word. */ | |
4951 | emit_insn (gen_subsi3 (out, out, GEN_INT (3))); | |
4952 | ||
4953 | emit_label (end_2_label); | |
4954 | emit_insn (gen_addsi3 (out, out, const1_rtx)); | |
4955 | ||
4956 | emit_label (end_3_label); | |
4957 | emit_insn (gen_addsi3 (out, out, const1_rtx)); | |
4958 | ||
4959 | emit_label (end_0_label); | |
4960 | } | |
4961 | \f | |
e075ae69 RH |
4962 | /* Clear stack slot assignments remembered from previous functions. |
4963 | This is called from INIT_EXPANDERS once before RTL is emitted for each | |
4964 | function. */ | |
4965 | ||
36edd3cc BS |
4966 | static void |
4967 | ix86_init_machine_status (p) | |
1526a060 | 4968 | struct function *p; |
e075ae69 RH |
4969 | { |
4970 | enum machine_mode mode; | |
4971 | int n; | |
36edd3cc BS |
4972 | p->machine |
4973 | = (struct machine_function *) xmalloc (sizeof (struct machine_function)); | |
e075ae69 RH |
4974 | |
4975 | for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE; | |
4976 | mode = (enum machine_mode) ((int) mode + 1)) | |
4977 | for (n = 0; n < MAX_386_STACK_LOCALS; n++) | |
4978 | ix86_stack_locals[(int) mode][n] = NULL_RTX; | |
e075ae69 RH |
4979 | } |
4980 | ||
1526a060 BS |
4981 | /* Mark machine specific bits of P for GC. */ |
4982 | static void | |
4983 | ix86_mark_machine_status (p) | |
4984 | struct function *p; | |
4985 | { | |
4986 | enum machine_mode mode; | |
4987 | int n; | |
4988 | ||
4989 | for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE; | |
4990 | mode = (enum machine_mode) ((int) mode + 1)) | |
4991 | for (n = 0; n < MAX_386_STACK_LOCALS; n++) | |
4992 | ggc_mark_rtx (p->machine->stack_locals[(int) mode][n]); | |
4993 | } | |
4994 | ||
e075ae69 RH |
4995 | /* Return a MEM corresponding to a stack slot with mode MODE. |
4996 | Allocate a new slot if necessary. | |
4997 | ||
4998 | The RTL for a function can have several slots available: N is | |
4999 | which slot to use. */ | |
5000 | ||
5001 | rtx | |
5002 | assign_386_stack_local (mode, n) | |
5003 | enum machine_mode mode; | |
5004 | int n; | |
5005 | { | |
5006 | if (n < 0 || n >= MAX_386_STACK_LOCALS) | |
5007 | abort (); | |
5008 | ||
5009 | if (ix86_stack_locals[(int) mode][n] == NULL_RTX) | |
5010 | ix86_stack_locals[(int) mode][n] | |
5011 | = assign_stack_local (mode, GET_MODE_SIZE (mode), 0); | |
5012 | ||
5013 | return ix86_stack_locals[(int) mode][n]; | |
5014 | } | |
5015 | \f | |
5016 | /* Calculate the length of the memory address in the instruction | |
5017 | encoding. Does not include the one-byte modrm, opcode, or prefix. */ | |
5018 | ||
5019 | static int | |
5020 | memory_address_length (addr) | |
5021 | rtx addr; | |
5022 | { | |
5023 | struct ix86_address parts; | |
5024 | rtx base, index, disp; | |
5025 | int len; | |
5026 | ||
5027 | if (GET_CODE (addr) == PRE_DEC | |
5028 | || GET_CODE (addr) == POST_INC) | |
5029 | return 0; | |
3f803cd9 | 5030 | |
e075ae69 RH |
5031 | if (! ix86_decompose_address (addr, &parts)) |
5032 | abort (); | |
3f803cd9 | 5033 | |
e075ae69 RH |
5034 | base = parts.base; |
5035 | index = parts.index; | |
5036 | disp = parts.disp; | |
5037 | len = 0; | |
3f803cd9 | 5038 | |
e075ae69 RH |
5039 | /* Register Indirect. */ |
5040 | if (base && !index && !disp) | |
5041 | { | |
5042 | /* Special cases: ebp and esp need the two-byte modrm form. */ | |
5043 | if (addr == stack_pointer_rtx | |
5044 | || addr == arg_pointer_rtx | |
5045 | || addr == frame_pointer_rtx) | |
5046 | len = 1; | |
3f803cd9 | 5047 | } |
e9a25f70 | 5048 | |
e075ae69 RH |
5049 | /* Direct Addressing. */ |
5050 | else if (disp && !base && !index) | |
5051 | len = 4; | |
5052 | ||
3f803cd9 SC |
5053 | else |
5054 | { | |
e075ae69 RH |
5055 | /* Find the length of the displacement constant. */ |
5056 | if (disp) | |
5057 | { | |
5058 | if (GET_CODE (disp) == CONST_INT | |
5059 | && CONST_OK_FOR_LETTER_P (INTVAL (disp), 'K')) | |
5060 | len = 1; | |
5061 | else | |
5062 | len = 4; | |
5063 | } | |
3f803cd9 | 5064 | |
e075ae69 RH |
5065 | /* An index requires the two-byte modrm form. */ |
5066 | if (index) | |
5067 | len += 1; | |
3f803cd9 SC |
5068 | } |
5069 | ||
e075ae69 RH |
5070 | return len; |
5071 | } | |
79325812 | 5072 | |
e075ae69 RH |
5073 | int |
5074 | ix86_attr_length_default (insn) | |
5075 | rtx insn; | |
5076 | { | |
5077 | enum attr_type type; | |
5078 | int len = 0, i; | |
5079 | ||
5080 | type = get_attr_type (insn); | |
5081 | extract_insn (insn); | |
5082 | switch (type) | |
5083 | { | |
5084 | case TYPE_INCDEC: | |
5085 | case TYPE_SETCC: | |
5086 | case TYPE_ICMOV: | |
5087 | case TYPE_FMOV: | |
5088 | case TYPE_FOP: | |
5089 | case TYPE_FCMP: | |
5090 | case TYPE_FOP1: | |
5091 | case TYPE_FMUL: | |
5092 | case TYPE_FDIV: | |
5093 | case TYPE_FSGN: | |
5094 | case TYPE_FPSPC: | |
5095 | case TYPE_FCMOV: | |
5096 | case TYPE_IBR: | |
5097 | break; | |
3f803cd9 | 5098 | |
e075ae69 RH |
5099 | case TYPE_ALU1: |
5100 | case TYPE_NEGNOT: | |
5101 | case TYPE_ALU: | |
5102 | case TYPE_ICMP: | |
5103 | case TYPE_IMOVX: | |
5104 | case TYPE_ISHIFT: | |
5105 | case TYPE_IMUL: | |
5106 | case TYPE_IDIV: | |
5107 | case TYPE_PUSH: | |
5108 | case TYPE_POP: | |
5109 | for (i = recog_n_operands - 1; i >= 0; --i) | |
5110 | if (CONSTANT_P (recog_operand[i])) | |
5111 | { | |
5112 | if (GET_CODE (recog_operand[i]) == CONST_INT | |
5113 | && CONST_OK_FOR_LETTER_P (INTVAL (recog_operand[i]), 'K')) | |
5114 | len += 1; | |
5115 | else | |
5116 | len += GET_MODE_SIZE (GET_MODE (recog_operand[0])); | |
5117 | } | |
5118 | break; | |
5119 | ||
5120 | case TYPE_IMOV: | |
5121 | if (CONSTANT_P (recog_operand[1])) | |
5122 | len += GET_MODE_SIZE (GET_MODE (recog_operand[0])); | |
5123 | break; | |
5124 | ||
5125 | case TYPE_CALL: | |
5126 | if (constant_call_address_operand (recog_operand[0])) | |
5127 | return 5; | |
5128 | break; | |
3f803cd9 | 5129 | |
e075ae69 RH |
5130 | case TYPE_CALLV: |
5131 | if (constant_call_address_operand (recog_operand[1])) | |
5132 | return 5; | |
5133 | break; | |
3f803cd9 | 5134 | |
e075ae69 RH |
5135 | case TYPE_LEA: |
5136 | len += memory_address_length (SET_SRC (single_set (insn))); | |
5137 | goto just_opcode; | |
3f803cd9 | 5138 | |
e075ae69 RH |
5139 | case TYPE_OTHER: |
5140 | case TYPE_MULTI: | |
5141 | return 15; | |
3f803cd9 | 5142 | |
5d3c4797 JL |
5143 | case TYPE_FXCH: |
5144 | if (STACK_TOP_P (recog_operand[0])) | |
5145 | return 2 + (REGNO (recog_operand[1]) != FIRST_STACK_REG + 1); | |
5146 | else | |
5147 | return 2 + (REGNO (recog_operand[0]) != FIRST_STACK_REG + 1); | |
5148 | ||
e075ae69 RH |
5149 | default: |
5150 | abort (); | |
5151 | } | |
5152 | ||
5153 | for (i = recog_n_operands - 1; i >= 0; --i) | |
5154 | if (GET_CODE (recog_operand[i]) == MEM) | |
5155 | { | |
5156 | len += memory_address_length (XEXP (recog_operand[i], 0)); | |
5157 | break; | |
5158 | } | |
5159 | ||
5160 | just_opcode: | |
5161 | len += get_attr_length_opcode (insn); | |
5162 | len += get_attr_length_prefix (insn); | |
5163 | ||
5164 | return len; | |
3f803cd9 | 5165 | } |
e075ae69 RH |
5166 | \f |
5167 | /* Return the maximum number of instructions a cpu can issue. */ | |
b657fc39 | 5168 | |
e075ae69 RH |
5169 | int |
5170 | ix86_issue_rate () | |
b657fc39 | 5171 | { |
e075ae69 | 5172 | switch (ix86_cpu) |
b657fc39 | 5173 | { |
e075ae69 RH |
5174 | case PROCESSOR_PENTIUM: |
5175 | case PROCESSOR_K6: | |
5176 | return 2; | |
79325812 | 5177 | |
e075ae69 RH |
5178 | case PROCESSOR_PENTIUMPRO: |
5179 | return 3; | |
b657fc39 | 5180 | |
b657fc39 | 5181 | default: |
e075ae69 | 5182 | return 1; |
b657fc39 | 5183 | } |
b657fc39 L |
5184 | } |
5185 | ||
e075ae69 RH |
5186 | /* A subroutine of ix86_adjust_cost -- return true iff INSN reads flags set |
5187 | by DEP_INSN and nothing set by DEP_INSN. */ | |
b657fc39 | 5188 | |
e075ae69 RH |
5189 | static int |
5190 | ix86_flags_dependant (insn, dep_insn, insn_type) | |
5191 | rtx insn, dep_insn; | |
5192 | enum attr_type insn_type; | |
5193 | { | |
5194 | rtx set, set2; | |
b657fc39 | 5195 | |
e075ae69 RH |
5196 | /* Simplify the test for uninteresting insns. */ |
5197 | if (insn_type != TYPE_SETCC | |
5198 | && insn_type != TYPE_ICMOV | |
5199 | && insn_type != TYPE_FCMOV | |
5200 | && insn_type != TYPE_IBR) | |
5201 | return 0; | |
b657fc39 | 5202 | |
e075ae69 RH |
5203 | if ((set = single_set (dep_insn)) != 0) |
5204 | { | |
5205 | set = SET_DEST (set); | |
5206 | set2 = NULL_RTX; | |
5207 | } | |
5208 | else if (GET_CODE (PATTERN (dep_insn)) == PARALLEL | |
5209 | && XVECLEN (PATTERN (dep_insn), 0) == 2 | |
5210 | && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 0)) == SET | |
5211 | && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 1)) == SET) | |
5212 | { | |
5213 | set = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0)); | |
5214 | set2 = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0)); | |
5215 | } | |
b657fc39 | 5216 | |
e075ae69 | 5217 | if (set && GET_CODE (set) == REG && REGNO (set) == FLAGS_REG) |
b657fc39 | 5218 | { |
e075ae69 RH |
5219 | /* This test is true if the dependant insn reads the flags but |
5220 | not any other potentially set register. */ | |
5221 | if (reg_overlap_mentioned_p (set, PATTERN (insn)) | |
5222 | && (!set2 || !reg_overlap_mentioned_p (set2, PATTERN (insn)))) | |
5223 | return 1; | |
5224 | } | |
b657fc39 | 5225 | |
e075ae69 RH |
5226 | return 0; |
5227 | } | |
b657fc39 | 5228 | |
e075ae69 RH |
5229 | /* A subroutine of ix86_adjust_cost -- return true iff INSN has a memory |
5230 | address with operands set by DEP_INSN. */ | |
5231 | ||
5232 | static int | |
5233 | ix86_agi_dependant (insn, dep_insn, insn_type) | |
5234 | rtx insn, dep_insn; | |
5235 | enum attr_type insn_type; | |
5236 | { | |
5237 | rtx addr; | |
5238 | ||
5239 | if (insn_type == TYPE_LEA) | |
5240 | addr = SET_SRC (single_set (insn)); | |
5241 | else | |
5242 | { | |
5243 | int i; | |
5244 | extract_insn (insn); | |
5245 | for (i = recog_n_operands - 1; i >= 0; --i) | |
5246 | if (GET_CODE (recog_operand[i]) == MEM) | |
5247 | { | |
5248 | addr = XEXP (recog_operand[i], 0); | |
5249 | goto found; | |
5250 | } | |
5251 | return 0; | |
5252 | found:; | |
b657fc39 L |
5253 | } |
5254 | ||
e075ae69 | 5255 | return modified_in_p (addr, dep_insn); |
b657fc39 | 5256 | } |
a269a03c JC |
5257 | |
5258 | int | |
e075ae69 | 5259 | ix86_adjust_cost (insn, link, dep_insn, cost) |
a269a03c JC |
5260 | rtx insn, link, dep_insn; |
5261 | int cost; | |
5262 | { | |
e075ae69 RH |
5263 | enum attr_type insn_type, dep_insn_type; |
5264 | rtx set, set2; | |
a269a03c | 5265 | |
e075ae69 RH |
5266 | /* We describe no anti or output depenancies. */ |
5267 | if (REG_NOTE_KIND (link) != 0) | |
5268 | return cost; | |
a269a03c | 5269 | |
e075ae69 RH |
5270 | /* If we can't recognize the insns, we can't really do anything. */ |
5271 | if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0) | |
5272 | return cost; | |
a269a03c | 5273 | |
e075ae69 RH |
5274 | insn_type = get_attr_type (insn); |
5275 | dep_insn_type = get_attr_type (dep_insn); | |
a269a03c JC |
5276 | |
5277 | switch (ix86_cpu) | |
5278 | { | |
5279 | case PROCESSOR_PENTIUM: | |
e075ae69 RH |
5280 | /* Address Generation Interlock adds a cycle of latency. */ |
5281 | if (ix86_agi_dependant (insn, dep_insn, insn_type)) | |
5282 | cost += 1; | |
5283 | ||
5284 | /* ??? Compares pair with jump/setcc. */ | |
5285 | if (ix86_flags_dependant (insn, dep_insn, insn_type)) | |
5286 | cost = 0; | |
5287 | ||
5288 | /* Floating point stores require value to be ready one cycle ealier. */ | |
5289 | if (insn_type == TYPE_FMOV | |
5290 | && get_attr_memory (insn) == MEMORY_STORE | |
5291 | && !ix86_agi_dependant (insn, dep_insn, insn_type)) | |
5292 | cost += 1; | |
5293 | break; | |
a269a03c | 5294 | |
e075ae69 RH |
5295 | case PROCESSOR_PENTIUMPRO: |
5296 | /* Since we can't represent delayed latencies of load+operation, | |
5297 | increase the cost here for non-imov insns. */ | |
5298 | if (dep_insn_type != TYPE_IMOV | |
5299 | && dep_insn_type != TYPE_FMOV | |
5300 | && get_attr_memory (dep_insn) == MEMORY_LOAD) | |
5301 | cost += 1; | |
5302 | ||
5303 | /* INT->FP conversion is expensive. */ | |
5304 | if (get_attr_fp_int_src (dep_insn)) | |
5305 | cost += 5; | |
5306 | ||
5307 | /* There is one cycle extra latency between an FP op and a store. */ | |
5308 | if (insn_type == TYPE_FMOV | |
5309 | && (set = single_set (dep_insn)) != NULL_RTX | |
5310 | && (set2 = single_set (insn)) != NULL_RTX | |
5311 | && rtx_equal_p (SET_DEST (set), SET_SRC (set2)) | |
5312 | && GET_CODE (SET_DEST (set2)) == MEM) | |
5313 | cost += 1; | |
5314 | break; | |
a269a03c | 5315 | |
e075ae69 RH |
5316 | case PROCESSOR_K6: |
5317 | /* The esp dependency is resolved before the instruction is really | |
5318 | finished. */ | |
5319 | if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP) | |
5320 | && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP)) | |
5321 | return 1; | |
a269a03c | 5322 | |
e075ae69 RH |
5323 | /* Since we can't represent delayed latencies of load+operation, |
5324 | increase the cost here for non-imov insns. */ | |
5325 | if (get_attr_memory (dep_insn) == MEMORY_LOAD) | |
5326 | cost += (dep_insn_type != TYPE_IMOV) ? 2 : 1; | |
5327 | ||
5328 | /* INT->FP conversion is expensive. */ | |
5329 | if (get_attr_fp_int_src (dep_insn)) | |
5330 | cost += 5; | |
a14003ee | 5331 | break; |
e075ae69 | 5332 | |
a269a03c | 5333 | default: |
a269a03c JC |
5334 | break; |
5335 | } | |
5336 | ||
5337 | return cost; | |
5338 | } | |
0a726ef1 | 5339 | |
e075ae69 RH |
5340 | static union |
5341 | { | |
5342 | struct ppro_sched_data | |
5343 | { | |
5344 | rtx decode[3]; | |
5345 | int issued_this_cycle; | |
5346 | } ppro; | |
5347 | } ix86_sched_data; | |
0a726ef1 | 5348 | |
e075ae69 RH |
5349 | static int |
5350 | ix86_safe_length (insn) | |
5351 | rtx insn; | |
5352 | { | |
5353 | if (recog_memoized (insn) >= 0) | |
5354 | return get_attr_length(insn); | |
5355 | else | |
5356 | return 128; | |
5357 | } | |
0a726ef1 | 5358 | |
e075ae69 RH |
5359 | static int |
5360 | ix86_safe_length_prefix (insn) | |
5361 | rtx insn; | |
5362 | { | |
5363 | if (recog_memoized (insn) >= 0) | |
5364 | return get_attr_length(insn); | |
5365 | else | |
5366 | return 0; | |
5367 | } | |
5368 | ||
5369 | static enum attr_memory | |
5370 | ix86_safe_memory (insn) | |
5371 | rtx insn; | |
5372 | { | |
5373 | if (recog_memoized (insn) >= 0) | |
5374 | return get_attr_memory(insn); | |
5375 | else | |
5376 | return MEMORY_UNKNOWN; | |
5377 | } | |
0a726ef1 | 5378 | |
e075ae69 RH |
5379 | static enum attr_pent_pair |
5380 | ix86_safe_pent_pair (insn) | |
5381 | rtx insn; | |
5382 | { | |
5383 | if (recog_memoized (insn) >= 0) | |
5384 | return get_attr_pent_pair(insn); | |
5385 | else | |
5386 | return PENT_PAIR_NP; | |
5387 | } | |
0a726ef1 | 5388 | |
e075ae69 RH |
5389 | static enum attr_ppro_uops |
5390 | ix86_safe_ppro_uops (insn) | |
5391 | rtx insn; | |
5392 | { | |
5393 | if (recog_memoized (insn) >= 0) | |
5394 | return get_attr_ppro_uops (insn); | |
5395 | else | |
5396 | return PPRO_UOPS_MANY; | |
5397 | } | |
0a726ef1 | 5398 | |
e075ae69 RH |
5399 | static void |
5400 | ix86_dump_ppro_packet (dump) | |
5401 | FILE *dump; | |
0a726ef1 | 5402 | { |
e075ae69 | 5403 | if (ix86_sched_data.ppro.decode[0]) |
0a726ef1 | 5404 | { |
e075ae69 RH |
5405 | fprintf (dump, "PPRO packet: %d", |
5406 | INSN_UID (ix86_sched_data.ppro.decode[0])); | |
5407 | if (ix86_sched_data.ppro.decode[1]) | |
5408 | fprintf (dump, " %d", INSN_UID (ix86_sched_data.ppro.decode[1])); | |
5409 | if (ix86_sched_data.ppro.decode[2]) | |
5410 | fprintf (dump, " %d", INSN_UID (ix86_sched_data.ppro.decode[2])); | |
5411 | fputc ('\n', dump); | |
5412 | } | |
5413 | } | |
0a726ef1 | 5414 | |
e075ae69 | 5415 | /* We're beginning a new block. Initialize data structures as necessary. */ |
0a726ef1 | 5416 | |
e075ae69 RH |
5417 | void |
5418 | ix86_sched_init (dump, sched_verbose) | |
5419 | FILE *dump ATTRIBUTE_UNUSED; | |
5420 | int sched_verbose ATTRIBUTE_UNUSED; | |
5421 | { | |
5422 | memset (&ix86_sched_data, 0, sizeof (ix86_sched_data)); | |
5423 | } | |
5424 | ||
5425 | /* Shift INSN to SLOT, and shift everything else down. */ | |
5426 | ||
5427 | static void | |
5428 | ix86_reorder_insn (insnp, slot) | |
5429 | rtx *insnp, *slot; | |
5430 | { | |
5431 | if (insnp != slot) | |
5432 | { | |
5433 | rtx insn = *insnp; | |
5434 | do | |
5435 | insnp[0] = insnp[1]; | |
5436 | while (++insnp != slot); | |
5437 | *insnp = insn; | |
0a726ef1 | 5438 | } |
e075ae69 RH |
5439 | } |
5440 | ||
5441 | /* Find an instruction with given pairability and minimal amount of cycles | |
5442 | lost by the fact that the CPU waits for both pipelines to finish before | |
5443 | reading next instructions. Also take care that both instructions together | |
5444 | can not exceed 7 bytes. */ | |
5445 | ||
5446 | static rtx * | |
5447 | ix86_pent_find_pair (e_ready, ready, type, first) | |
5448 | rtx *e_ready; | |
5449 | rtx *ready; | |
5450 | enum attr_pent_pair type; | |
5451 | rtx first; | |
5452 | { | |
5453 | int mincycles, cycles; | |
5454 | enum attr_pent_pair tmp; | |
5455 | enum attr_memory memory; | |
5456 | rtx *insnp, *bestinsnp = NULL; | |
0a726ef1 | 5457 | |
e075ae69 RH |
5458 | if (ix86_safe_length (first) > 7 + ix86_safe_length_prefix (first)) |
5459 | return NULL; | |
0a726ef1 | 5460 | |
e075ae69 RH |
5461 | memory = ix86_safe_memory (first); |
5462 | cycles = result_ready_cost (first); | |
5463 | mincycles = INT_MAX; | |
5464 | ||
5465 | for (insnp = e_ready; insnp >= ready && mincycles; --insnp) | |
5466 | if ((tmp = ix86_safe_pent_pair (*insnp)) == type | |
5467 | && ix86_safe_length (*insnp) <= 7 + ix86_safe_length_prefix (*insnp)) | |
6ec6d558 | 5468 | { |
e075ae69 RH |
5469 | enum attr_memory second_memory; |
5470 | int secondcycles, currentcycles; | |
5471 | ||
5472 | second_memory = ix86_safe_memory (*insnp); | |
5473 | secondcycles = result_ready_cost (*insnp); | |
5474 | currentcycles = abs (cycles - secondcycles); | |
5475 | ||
5476 | if (secondcycles >= 1 && cycles >= 1) | |
6ec6d558 | 5477 | { |
e075ae69 RH |
5478 | /* Two read/modify/write instructions together takes two |
5479 | cycles longer. */ | |
5480 | if (memory == MEMORY_BOTH && second_memory == MEMORY_BOTH) | |
5481 | currentcycles += 2; | |
5482 | ||
5483 | /* Read modify/write instruction followed by read/modify | |
5484 | takes one cycle longer. */ | |
5485 | if (memory == MEMORY_BOTH && second_memory == MEMORY_LOAD | |
5486 | && tmp != PENT_PAIR_UV | |
5487 | && ix86_safe_pent_pair (first) != PENT_PAIR_UV) | |
5488 | currentcycles += 1; | |
6ec6d558 | 5489 | } |
e075ae69 RH |
5490 | if (currentcycles < mincycles) |
5491 | bestinsnp = insnp, mincycles = currentcycles; | |
6ec6d558 | 5492 | } |
0a726ef1 | 5493 | |
e075ae69 RH |
5494 | return bestinsnp; |
5495 | } | |
5496 | ||
5497 | /* We are about to being issuing insns for this clock cycle. | |
5498 | Override the default sort algorithm to better slot instructions. */ | |
5499 | ||
5500 | int | |
5501 | ix86_sched_reorder (dump, sched_verbose, ready, n_ready, clock_var) | |
5502 | FILE *dump ATTRIBUTE_UNUSED; | |
5503 | int sched_verbose ATTRIBUTE_UNUSED; | |
5504 | rtx *ready; | |
5505 | int n_ready, clock_var; | |
5506 | { | |
5507 | rtx *e_ready = ready + n_ready - 1; | |
5508 | rtx *insnp; | |
5509 | int i; | |
5510 | ||
5511 | if (n_ready < 2) | |
5512 | goto out; | |
5513 | ||
5514 | switch (ix86_cpu) | |
5515 | { | |
5516 | default: | |
5517 | goto out; | |
5518 | ||
5519 | case PROCESSOR_PENTIUM: | |
5520 | /* This wouldn't be necessary if Haifa knew that static insn ordering | |
5521 | is important to which pipe an insn is issued to. So we have to make | |
5522 | some minor rearrangements. */ | |
6ec6d558 | 5523 | { |
e075ae69 RH |
5524 | enum attr_pent_pair pair1, pair2; |
5525 | ||
5526 | pair1 = ix86_safe_pent_pair (*e_ready); | |
5527 | ||
5528 | /* If the first insn is non-pairable, let it be. */ | |
5529 | if (pair1 == PENT_PAIR_NP) | |
5530 | goto out; | |
5531 | pair2 = PENT_PAIR_NP; | |
5532 | ||
5533 | /* If the first insn is UV or PV pairable, search for a PU | |
5534 | insn to go with. */ | |
5535 | if (pair1 == PENT_PAIR_UV || pair1 == PENT_PAIR_PV) | |
5536 | { | |
5537 | insnp = ix86_pent_find_pair (e_ready-1, ready, | |
5538 | PENT_PAIR_PU, *e_ready); | |
5539 | if (insnp) | |
5540 | pair2 = PENT_PAIR_PU; | |
5541 | } | |
5542 | ||
5543 | /* If the first insn is PU or UV pairable, search for a PV | |
5544 | insn to go with. */ | |
5545 | if (pair2 == PENT_PAIR_NP | |
5546 | && (pair1 == PENT_PAIR_PU || pair1 == PENT_PAIR_UV)) | |
5547 | { | |
5548 | insnp = ix86_pent_find_pair (e_ready-1, ready, | |
5549 | PENT_PAIR_PV, *e_ready); | |
5550 | if (insnp) | |
5551 | pair2 = PENT_PAIR_PV; | |
5552 | } | |
5553 | ||
5554 | /* If the first insn is pairable, search for a UV | |
5555 | insn to go with. */ | |
5556 | if (pair2 == PENT_PAIR_NP) | |
6ec6d558 | 5557 | { |
e075ae69 RH |
5558 | insnp = ix86_pent_find_pair (e_ready-1, ready, |
5559 | PENT_PAIR_UV, *e_ready); | |
5560 | if (insnp) | |
5561 | pair2 = PENT_PAIR_UV; | |
6ec6d558 | 5562 | } |
e075ae69 RH |
5563 | |
5564 | if (pair2 == PENT_PAIR_NP) | |
5565 | goto out; | |
5566 | ||
5567 | /* Found something! Decide if we need to swap the order. */ | |
5568 | if (pair1 == PENT_PAIR_PV || pair2 == PENT_PAIR_PU | |
5569 | || (pair1 == PENT_PAIR_UV && pair2 == PENT_PAIR_UV | |
5570 | && ix86_safe_memory (*e_ready) == MEMORY_BOTH | |
5571 | && ix86_safe_memory (*insnp) == MEMORY_LOAD)) | |
5572 | ix86_reorder_insn (insnp, e_ready); | |
6ec6d558 | 5573 | else |
e075ae69 | 5574 | ix86_reorder_insn (insnp, e_ready - 1); |
6ec6d558 | 5575 | } |
e075ae69 | 5576 | break; |
0a726ef1 | 5577 | |
e075ae69 RH |
5578 | case PROCESSOR_PENTIUMPRO: |
5579 | { | |
5580 | rtx decode[3]; | |
5581 | enum attr_ppro_uops cur_uops; | |
5582 | int issued_this_cycle; | |
0a726ef1 | 5583 | |
e075ae69 RH |
5584 | /* At this point .ppro.decode contains the state of the three |
5585 | decoders from last "cycle". That is, those insns that were | |
5586 | actually independant. But here we're scheduling for the | |
5587 | decoder, and we may find things that are decodable in the | |
5588 | same cycle. */ | |
fb693d44 | 5589 | |
e075ae69 RH |
5590 | memcpy (decode, ix86_sched_data.ppro.decode, sizeof(decode)); |
5591 | issued_this_cycle = 0; | |
fb693d44 | 5592 | |
e075ae69 RH |
5593 | insnp = e_ready; |
5594 | cur_uops = ix86_safe_ppro_uops (*insnp); | |
fb693d44 | 5595 | |
e075ae69 RH |
5596 | /* If the decoders are empty, and we've a complex insn at the |
5597 | head of the priority queue, let it issue without complaint. */ | |
5598 | if (decode[0] == NULL) | |
5599 | { | |
5600 | if (cur_uops == PPRO_UOPS_MANY) | |
5601 | { | |
5602 | decode[0] = *insnp; | |
5603 | goto ppro_done; | |
5604 | } | |
fb693d44 | 5605 | |
e075ae69 RH |
5606 | /* Otherwise, search for a 2-4 uop unsn to issue. */ |
5607 | while (cur_uops != PPRO_UOPS_FEW) | |
5608 | { | |
5609 | if (insnp == ready) | |
5610 | break; | |
5611 | cur_uops = ix86_safe_ppro_uops (*--insnp); | |
5612 | } | |
fb693d44 | 5613 | |
e075ae69 RH |
5614 | /* If so, move it to the head of the line. */ |
5615 | if (cur_uops == PPRO_UOPS_FEW) | |
5616 | ix86_reorder_insn (insnp, e_ready); | |
fb693d44 | 5617 | |
e075ae69 RH |
5618 | /* Issue the head of the queue. */ |
5619 | issued_this_cycle = 1; | |
5620 | decode[0] = *e_ready--; | |
5621 | } | |
fb693d44 | 5622 | |
e075ae69 RH |
5623 | /* Look for simple insns to fill in the other two slots. */ |
5624 | for (i = 1; i < 3; ++i) | |
5625 | if (decode[i] == NULL) | |
5626 | { | |
5627 | if (ready >= e_ready) | |
5628 | goto ppro_done; | |
fb693d44 | 5629 | |
e075ae69 RH |
5630 | insnp = e_ready; |
5631 | cur_uops = ix86_safe_ppro_uops (*insnp); | |
5632 | while (cur_uops != PPRO_UOPS_ONE) | |
5633 | { | |
5634 | if (insnp == ready) | |
5635 | break; | |
5636 | cur_uops = ix86_safe_ppro_uops (*--insnp); | |
5637 | } | |
5638 | ||
5639 | /* Found one. Move it to the head of the queue and issue it. */ | |
5640 | if (cur_uops == PPRO_UOPS_ONE) | |
5641 | { | |
5642 | ix86_reorder_insn (insnp, e_ready); | |
5643 | decode[i] = *e_ready--; | |
5644 | issued_this_cycle++; | |
5645 | continue; | |
5646 | } | |
5647 | ||
5648 | /* ??? Didn't find one. Ideally, here we would do a lazy split | |
5649 | of 2-uop insns, issue one and queue the other. */ | |
5650 | } | |
5651 | ||
5652 | ppro_done: | |
5653 | if (issued_this_cycle == 0) | |
5654 | issued_this_cycle = 1; | |
5655 | ix86_sched_data.ppro.issued_this_cycle = issued_this_cycle; | |
5656 | } | |
5657 | break; | |
fb693d44 RH |
5658 | } |
5659 | ||
e075ae69 RH |
5660 | out: |
5661 | return ix86_issue_rate (); | |
5662 | } | |
fb693d44 | 5663 | |
e075ae69 RH |
5664 | /* We are about to issue INSN. Return the number of insns left on the |
5665 | ready queue that can be issued this cycle. */ | |
b222082e | 5666 | |
e075ae69 RH |
5667 | int |
5668 | ix86_variable_issue (dump, sched_verbose, insn, can_issue_more) | |
5669 | FILE *dump; | |
5670 | int sched_verbose; | |
5671 | rtx insn; | |
5672 | int can_issue_more; | |
5673 | { | |
5674 | int i; | |
5675 | switch (ix86_cpu) | |
fb693d44 | 5676 | { |
e075ae69 RH |
5677 | default: |
5678 | return can_issue_more - 1; | |
fb693d44 | 5679 | |
e075ae69 RH |
5680 | case PROCESSOR_PENTIUMPRO: |
5681 | { | |
5682 | enum attr_ppro_uops uops = ix86_safe_ppro_uops (insn); | |
fb693d44 | 5683 | |
e075ae69 RH |
5684 | if (uops == PPRO_UOPS_MANY) |
5685 | { | |
5686 | if (sched_verbose) | |
5687 | ix86_dump_ppro_packet (dump); | |
5688 | ix86_sched_data.ppro.decode[0] = insn; | |
5689 | ix86_sched_data.ppro.decode[1] = NULL; | |
5690 | ix86_sched_data.ppro.decode[2] = NULL; | |
5691 | if (sched_verbose) | |
5692 | ix86_dump_ppro_packet (dump); | |
5693 | ix86_sched_data.ppro.decode[0] = NULL; | |
5694 | } | |
5695 | else if (uops == PPRO_UOPS_FEW) | |
5696 | { | |
5697 | if (sched_verbose) | |
5698 | ix86_dump_ppro_packet (dump); | |
5699 | ix86_sched_data.ppro.decode[0] = insn; | |
5700 | ix86_sched_data.ppro.decode[1] = NULL; | |
5701 | ix86_sched_data.ppro.decode[2] = NULL; | |
5702 | } | |
5703 | else | |
5704 | { | |
5705 | for (i = 0; i < 3; ++i) | |
5706 | if (ix86_sched_data.ppro.decode[i] == NULL) | |
5707 | { | |
5708 | ix86_sched_data.ppro.decode[i] = insn; | |
5709 | break; | |
5710 | } | |
5711 | if (i == 3) | |
5712 | abort (); | |
5713 | if (i == 2) | |
5714 | { | |
5715 | if (sched_verbose) | |
5716 | ix86_dump_ppro_packet (dump); | |
5717 | ix86_sched_data.ppro.decode[0] = NULL; | |
5718 | ix86_sched_data.ppro.decode[1] = NULL; | |
5719 | ix86_sched_data.ppro.decode[2] = NULL; | |
5720 | } | |
5721 | } | |
5722 | } | |
5723 | return --ix86_sched_data.ppro.issued_this_cycle; | |
5724 | } | |
fb693d44 | 5725 | } |