]>
Commit | Line | Data |
---|---|---|
886c62d1 JVA |
1 | ;; GCC machine description for Intel 80386. |
2 | ;; Copyright (C) 1988 Free Software Foundation, Inc. | |
3 | ;; Mostly by William Schelter. | |
4 | ||
5 | ;; This file is part of GNU CC. | |
6 | ||
7 | ;; GNU CC is free software; you can redistribute it and/or modify | |
8 | ;; it under the terms of the GNU General Public License as published by | |
9 | ;; the Free Software Foundation; either version 2, or (at your option) | |
10 | ;; any later version. | |
11 | ||
12 | ;; GNU CC is distributed in the hope that it will be useful, | |
13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | ;; GNU General Public License for more details. | |
16 | ||
17 | ;; You should have received a copy of the GNU General Public License | |
18 | ;; along with GNU CC; see the file COPYING. If not, write to | |
19 | ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | ||
21 | ||
4af3895e JVA |
22 | ;; The original PO technology requires these to be ordered by speed, |
23 | ;; so that assigner will pick the fastest. | |
886c62d1 | 24 | |
4af3895e | 25 | ;; See file "rtl.def" for documentation on define_insn, match_*, et. al. |
886c62d1 | 26 | |
4af3895e JVA |
27 | ;; Macro #define NOTICE_UPDATE_CC in file i386.h handles condition code |
28 | ;; updates for most instructions. | |
886c62d1 | 29 | |
4af3895e JVA |
30 | ;; Macro REG_CLASS_FROM_LETTER in file i386.h defines the register |
31 | ;; constraint letters. | |
886c62d1 JVA |
32 | |
33 | ;; the special asm out single letter directives following a '%' are: | |
4af3895e JVA |
34 | ;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of |
35 | ;; operands[1]. | |
36 | ;; 'L' Print the opcode suffix for a 32-bit integer opcode. | |
37 | ;; 'W' Print the opcode suffix for a 16-bit integer opcode. | |
38 | ;; 'B' Print the opcode suffix for an 8-bit integer opcode. | |
39 | ;; 'S' Print the opcode suffix for a 32-bit float opcode. | |
40 | ;; 'Q' Print the opcode suffix for a 64-bit float opcode. | |
41 | ||
42 | ;; 'b' Print the QImode name of the register for the indicated operand. | |
43 | ;; %b0 would print %al if operands[0] is reg 0. | |
44 | ;; 'w' Likewise, print the HImode name of the register. | |
45 | ;; 'k' Likewise, print the SImode name of the register. | |
46 | ;; 'h' Print the QImode name for a "high" register, either ah, bh, ch or dh. | |
47 | ;; 'y' Print "st(0)" instead of "st" as a register. | |
48 | ||
49 | ;; UNSPEC usage: | |
50 | ;; 0 This is a `scas' operation. The mode of the UNSPEC is always SImode. | |
51 | ;; operand 0 is the memory address to scan. | |
52 | ;; operand 1 is a register containing the value to scan for. The mode | |
53 | ;; of the scas opcode will be the same as the mode of this operand. | |
54 | ;; operand 2 is the known alignment of operand 0. | |
886c62d1 JVA |
55 | |
56 | \f | |
886c62d1 JVA |
57 | ;; "movl MEM,REG / testl REG,REG" is faster on a 486 than "cmpl $0,MEM". |
58 | ;; But restricting MEM here would mean that gcc could not remove a redundant | |
59 | ;; test in cases like "incl MEM / je TARGET". | |
60 | ;; | |
61 | ;; We don't want to allow a constant operand for test insns because | |
62 | ;; (set (cc0) (const_int foo)) has no mode information. Such insns will | |
63 | ;; be folded while optimizing anyway. | |
64 | ||
c572e5ba JVA |
65 | ;; All test insns have expanders that save the operands away without |
66 | ;; actually generating RTL. The bCOND or sCOND (emitted immediately | |
67 | ;; after the tstM or cmp) will actually emit the tstM or cmpM. | |
68 | ||
69 | (define_insn "tstsi_cc" | |
886c62d1 JVA |
70 | [(set (cc0) |
71 | (match_operand:SI 0 "nonimmediate_operand" "rm"))] | |
72 | "" | |
73 | "* | |
74 | { | |
75 | if (REG_P (operands[0])) | |
76 | return AS2 (test%L0,%0,%0); | |
77 | ||
78 | operands[1] = const0_rtx; | |
79 | return AS2 (cmp%L0,%1,%0); | |
80 | }") | |
81 | ||
c572e5ba JVA |
82 | (define_expand "tstsi" |
83 | [(set (cc0) | |
84 | (match_operand:SI 0 "nonimmediate_operand" ""))] | |
85 | "" | |
86 | " | |
87 | { | |
88 | i386_compare_gen = gen_tstsi_cc; | |
89 | i386_compare_op0 = operands[0]; | |
90 | DONE; | |
91 | }") | |
92 | ||
93 | (define_insn "tsthi_cc" | |
886c62d1 JVA |
94 | [(set (cc0) |
95 | (match_operand:HI 0 "nonimmediate_operand" "rm"))] | |
96 | "" | |
97 | "* | |
98 | { | |
99 | if (REG_P (operands[0])) | |
100 | return AS2 (test%W0,%0,%0); | |
101 | ||
102 | operands[1] = const0_rtx; | |
103 | return AS2 (cmp%W0,%1,%0); | |
104 | }") | |
105 | ||
c572e5ba JVA |
106 | (define_expand "tsthi" |
107 | [(set (cc0) | |
108 | (match_operand:HI 0 "nonimmediate_operand" ""))] | |
109 | "" | |
110 | " | |
111 | { | |
112 | i386_compare_gen = gen_tsthi_cc; | |
113 | i386_compare_op0 = operands[0]; | |
114 | DONE; | |
115 | }") | |
116 | ||
117 | (define_insn "tstqi_cc" | |
886c62d1 JVA |
118 | [(set (cc0) |
119 | (match_operand:QI 0 "nonimmediate_operand" "qm"))] | |
120 | "" | |
121 | "* | |
122 | { | |
123 | if (REG_P (operands[0])) | |
124 | return AS2 (test%B0,%0,%0); | |
125 | ||
126 | operands[1] = const0_rtx; | |
127 | return AS2 (cmp%B0,%1,%0); | |
128 | }") | |
129 | ||
c572e5ba JVA |
130 | (define_expand "tstqi" |
131 | [(set (cc0) | |
132 | (match_operand:QI 0 "nonimmediate_operand" ""))] | |
133 | "" | |
134 | " | |
135 | { | |
136 | i386_compare_gen = gen_tstqi_cc; | |
137 | i386_compare_op0 = operands[0]; | |
138 | DONE; | |
139 | }") | |
140 | ||
141 | (define_insn "tstsf_cc" | |
886c62d1 JVA |
142 | [(set (cc0) |
143 | (match_operand:SF 0 "register_operand" "f")) | |
144 | (clobber (match_scratch:HI 1 "=a"))] | |
c572e5ba | 145 | "TARGET_80387 && ! TARGET_IEEE_FP" |
886c62d1 JVA |
146 | "* |
147 | { | |
148 | if (! STACK_TOP_P (operands[0])) | |
149 | abort (); | |
150 | ||
151 | output_asm_insn (\"ftst\", operands); | |
886c62d1 JVA |
152 | |
153 | if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) | |
154 | output_asm_insn (AS1 (fstp,%y0), operands); | |
155 | ||
c572e5ba JVA |
156 | return (char *) output_fp_cc0_set (insn); |
157 | }") | |
158 | ||
159 | ;; Don't generate tstsf if generating IEEE code, since the `ftst' opcode | |
160 | ;; isn't IEEE compliant. | |
886c62d1 | 161 | |
c572e5ba JVA |
162 | (define_expand "tstsf" |
163 | [(parallel [(set (cc0) | |
164 | (match_operand:SF 0 "register_operand" "")) | |
165 | (clobber (match_scratch:HI 1 ""))])] | |
166 | "TARGET_80387 && ! TARGET_IEEE_FP" | |
167 | " | |
168 | { | |
169 | i386_compare_gen = gen_tstsf_cc; | |
170 | i386_compare_op0 = operands[0]; | |
171 | DONE; | |
886c62d1 JVA |
172 | }") |
173 | ||
c572e5ba | 174 | (define_insn "tstdf_cc" |
886c62d1 JVA |
175 | [(set (cc0) |
176 | (match_operand:DF 0 "register_operand" "f")) | |
177 | (clobber (match_scratch:HI 1 "=a"))] | |
c572e5ba | 178 | "TARGET_80387 && ! TARGET_IEEE_FP" |
886c62d1 JVA |
179 | "* |
180 | { | |
181 | if (! STACK_TOP_P (operands[0])) | |
182 | abort (); | |
183 | ||
184 | output_asm_insn (\"ftst\", operands); | |
886c62d1 JVA |
185 | |
186 | if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) | |
187 | output_asm_insn (AS1 (fstp,%y0), operands); | |
188 | ||
c572e5ba JVA |
189 | return (char *) output_fp_cc0_set (insn); |
190 | }") | |
886c62d1 | 191 | |
c572e5ba JVA |
192 | ;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode |
193 | ;; isn't IEEE compliant. | |
194 | ||
195 | (define_expand "tstdf" | |
196 | [(parallel [(set (cc0) | |
197 | (match_operand:DF 0 "register_operand" "")) | |
198 | (clobber (match_scratch:HI 1 ""))])] | |
199 | "TARGET_80387 && ! TARGET_IEEE_FP" | |
200 | " | |
201 | { | |
202 | i386_compare_gen = gen_tstdf_cc; | |
203 | i386_compare_op0 = operands[0]; | |
204 | DONE; | |
886c62d1 JVA |
205 | }") |
206 | \f | |
c572e5ba JVA |
207 | ;;- compare instructions. See comments above tstM patterns about |
208 | ;; expansion of these insns. | |
886c62d1 | 209 | |
c572e5ba | 210 | (define_insn "cmpsi_cc" |
886c62d1 | 211 | [(set (cc0) |
c572e5ba JVA |
212 | (compare:CC (match_operand:SI 0 "nonimmediate_operand" "mr,ri") |
213 | (match_operand:SI 1 "general_operand" "ri,mr")))] | |
886c62d1 JVA |
214 | "" |
215 | "* | |
216 | { | |
217 | if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM) | |
218 | { | |
219 | cc_status.flags |= CC_REVERSED; | |
220 | return AS2 (cmp%L0,%0,%1); | |
221 | } | |
222 | return AS2 (cmp%L0,%1,%0); | |
223 | }") | |
224 | ||
c572e5ba | 225 | (define_expand "cmpsi" |
886c62d1 | 226 | [(set (cc0) |
c572e5ba JVA |
227 | (compare:CC (match_operand:SI 0 "nonimmediate_operand" "") |
228 | (match_operand:SI 1 "general_operand" "")))] | |
229 | "" | |
230 | " | |
231 | { | |
232 | i386_compare_gen = gen_cmpsi_cc; | |
233 | i386_compare_op0 = operands[0]; | |
234 | i386_compare_op1 = operands[1]; | |
235 | DONE; | |
236 | }") | |
237 | ||
238 | (define_insn "cmphi_cc" | |
239 | [(set (cc0) | |
240 | (compare:CC (match_operand:HI 0 "nonimmediate_operand" "mr,ri") | |
241 | (match_operand:HI 1 "general_operand" "ri,mr")))] | |
886c62d1 JVA |
242 | "" |
243 | "* | |
244 | { | |
245 | if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM) | |
246 | { | |
247 | cc_status.flags |= CC_REVERSED; | |
248 | return AS2 (cmp%W0,%0,%1); | |
249 | } | |
250 | return AS2 (cmp%W0,%1,%0); | |
251 | }") | |
252 | ||
c572e5ba | 253 | (define_expand "cmphi" |
886c62d1 | 254 | [(set (cc0) |
c572e5ba JVA |
255 | (compare:CC (match_operand:HI 0 "nonimmediate_operand" "") |
256 | (match_operand:HI 1 "general_operand" "")))] | |
257 | "" | |
258 | " | |
259 | { | |
260 | i386_compare_gen = gen_cmphi_cc; | |
261 | i386_compare_op0 = operands[0]; | |
262 | i386_compare_op1 = operands[1]; | |
263 | DONE; | |
264 | }") | |
265 | ||
266 | (define_insn "cmpqi_cc" | |
267 | [(set (cc0) | |
268 | (compare:CC (match_operand:QI 0 "nonimmediate_operand" "qn,mq") | |
269 | (match_operand:QI 1 "general_operand" "qm,nq")))] | |
886c62d1 JVA |
270 | "" |
271 | "* | |
272 | { | |
273 | if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM) | |
274 | { | |
275 | cc_status.flags |= CC_REVERSED; | |
276 | return AS2 (cmp%B0,%0,%1); | |
277 | } | |
278 | return AS2 (cmp%B0,%1,%0); | |
279 | }") | |
280 | ||
c572e5ba JVA |
281 | (define_expand "cmpqi" |
282 | [(set (cc0) | |
283 | (compare:CC (match_operand:QI 0 "nonimmediate_operand" "") | |
284 | (match_operand:QI 1 "general_operand" "")))] | |
285 | "" | |
286 | " | |
287 | { | |
288 | i386_compare_gen = gen_cmpqi_cc; | |
289 | i386_compare_op0 = operands[0]; | |
290 | i386_compare_op1 = operands[1]; | |
291 | DONE; | |
292 | }") | |
293 | ||
886c62d1 JVA |
294 | ;; These implement float point compares. For each of DFmode and |
295 | ;; SFmode, there is the normal insn, and an insn where the second operand | |
296 | ;; is converted to the desired mode. | |
297 | ||
c572e5ba JVA |
298 | (define_insn "cmpdf_cc" |
299 | [(set (cc0) | |
300 | (compare:CC (match_operand:DF 0 "register_operand" "f") | |
301 | (match_operand:DF 1 "nonimmediate_operand" "fm"))) | |
302 | (clobber (match_scratch:HI 2 "=a"))] | |
886c62d1 | 303 | "TARGET_80387" |
c572e5ba | 304 | "* return (char *) output_float_compare (insn, operands);") |
886c62d1 | 305 | |
c572e5ba JVA |
306 | (define_insn "" |
307 | [(set (cc0) | |
308 | (compare:CC (match_operand:DF 0 "register_operand" "f,f") | |
309 | (float:DF | |
310 | (match_operand:SI 1 "nonimmediate_operand" "m,!*r")))) | |
311 | (clobber (match_scratch:HI 2 "=a,a"))] | |
886c62d1 | 312 | "TARGET_80387" |
c572e5ba | 313 | "* return (char *) output_float_compare (insn, operands);") |
886c62d1 | 314 | |
c572e5ba JVA |
315 | (define_insn "" |
316 | [(set (cc0) | |
317 | (compare:CC (match_operand:DF 0 "register_operand" "f,f") | |
318 | (float_extend:DF | |
319 | (match_operand:SF 1 "nonimmediate_operand" "fm,!*r")))) | |
320 | (clobber (match_scratch:HI 2 "=a,a"))] | |
321 | "TARGET_80387" | |
322 | "* return (char *) output_float_compare (insn, operands);") | |
2bb7a0f5 | 323 | |
886c62d1 JVA |
324 | (define_insn "" |
325 | [(set (cc0) | |
c572e5ba JVA |
326 | (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f") |
327 | (match_operand:DF 1 "register_operand" "f"))) | |
886c62d1 JVA |
328 | (clobber (match_scratch:HI 2 "=a"))] |
329 | "TARGET_80387" | |
330 | "* return (char *) output_float_compare (insn, operands);") | |
331 | ||
332 | (define_insn "" | |
333 | [(set (cc0) | |
c572e5ba JVA |
334 | (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f") |
335 | (float_extend:DF | |
336 | (match_operand:SF 1 "register_operand" "f")))) | |
337 | (clobber (match_scratch:HI 2 "=a"))] | |
338 | "TARGET_80387" | |
339 | "* return (char *) output_float_compare (insn, operands);") | |
340 | ||
341 | (define_insn "cmpsf_cc" | |
342 | [(set (cc0) | |
343 | (compare:CC (match_operand:SF 0 "register_operand" "f") | |
344 | (match_operand:SF 1 "nonimmediate_operand" "fm"))) | |
345 | (clobber (match_scratch:HI 2 "=a"))] | |
886c62d1 JVA |
346 | "TARGET_80387" |
347 | "* return (char *) output_float_compare (insn, operands);") | |
348 | ||
349 | (define_insn "" | |
350 | [(set (cc0) | |
c572e5ba JVA |
351 | (compare:CC (match_operand:SF 0 "register_operand" "f,f") |
352 | (float:SF | |
353 | (match_operand:SI 1 "nonimmediate_operand" "m,!*r")))) | |
886c62d1 JVA |
354 | (clobber (match_scratch:HI 2 "=a,a"))] |
355 | "TARGET_80387" | |
356 | "* return (char *) output_float_compare (insn, operands);") | |
357 | ||
358 | (define_insn "" | |
359 | [(set (cc0) | |
c572e5ba JVA |
360 | (compare:CCFPEQ (match_operand:SF 0 "register_operand" "f") |
361 | (match_operand:SF 1 "register_operand" "f"))) | |
886c62d1 JVA |
362 | (clobber (match_scratch:HI 2 "=a"))] |
363 | "TARGET_80387" | |
364 | "* return (char *) output_float_compare (insn, operands);") | |
365 | ||
c572e5ba | 366 | (define_expand "cmpdf" |
886c62d1 | 367 | [(set (cc0) |
c572e5ba JVA |
368 | (compare:CC (match_operand:DF 0 "register_operand" "") |
369 | (match_operand:DF 1 "nonimmediate_operand" "")))] | |
886c62d1 | 370 | "TARGET_80387" |
c572e5ba JVA |
371 | " |
372 | { | |
373 | i386_compare_gen = gen_cmpdf_cc; | |
374 | i386_compare_gen_eq = gen_cmpdf_ccfpeq; | |
375 | i386_compare_op0 = operands[0]; | |
376 | i386_compare_op1 = operands[1]; | |
377 | DONE; | |
378 | }") | |
379 | ||
380 | (define_expand "cmpsf" | |
381 | [(set (cc0) | |
382 | (compare:CC (match_operand:SF 0 "register_operand" "") | |
383 | (match_operand:SF 1 "nonimmediate_operand" "")))] | |
384 | "TARGET_80387" | |
385 | " | |
386 | { | |
387 | i386_compare_gen = gen_cmpsf_cc; | |
388 | i386_compare_gen_eq = gen_cmpsf_ccfpeq; | |
389 | i386_compare_op0 = operands[0]; | |
390 | i386_compare_op1 = operands[1]; | |
391 | DONE; | |
392 | }") | |
393 | ||
394 | (define_expand "cmpdf_ccfpeq" | |
395 | [(parallel [(set (cc0) | |
396 | (compare:CCFPEQ (match_operand:DF 0 "register_operand" "") | |
397 | (match_operand:DF 1 "register_operand" ""))) | |
398 | (clobber (match_scratch:HI 2 ""))])] | |
399 | "TARGET_80387" | |
400 | " | |
401 | { | |
402 | if (! register_operand (operands[1], DFmode)) | |
403 | operands[1] = copy_to_mode_reg (DFmode, operands[1]); | |
404 | }") | |
405 | ||
406 | (define_expand "cmpsf_ccfpeq" | |
407 | [(parallel [(set (cc0) | |
408 | (compare:CCFPEQ (match_operand:SF 0 "register_operand" "") | |
409 | (match_operand:SF 1 "register_operand" ""))) | |
410 | (clobber (match_scratch:HI 2 ""))])] | |
411 | "TARGET_80387" | |
412 | " | |
413 | { | |
414 | if (! register_operand (operands[1], SFmode)) | |
415 | operands[1] = copy_to_mode_reg (SFmode, operands[1]); | |
416 | }") | |
886c62d1 JVA |
417 | \f |
418 | ;; logical compare | |
419 | ||
886c62d1 JVA |
420 | (define_insn "" |
421 | [(set (cc0) | |
b4ac57ab | 422 | (and:SI (match_operand:SI 0 "general_operand" "%ro") |
886c62d1 JVA |
423 | (match_operand:SI 1 "general_operand" "ri")))] |
424 | "" | |
425 | "* | |
426 | { | |
427 | /* For small integers, we may actually use testb. */ | |
428 | if (GET_CODE (operands[1]) == CONST_INT | |
b4ac57ab RS |
429 | && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) |
430 | && ! NON_QI_REG_P (operands[0])) | |
886c62d1 JVA |
431 | { |
432 | /* We may set the sign bit spuriously. */ | |
886c62d1 | 433 | |
b4ac57ab RS |
434 | if ((INTVAL (operands[1]) & ~0xff) == 0) |
435 | { | |
436 | cc_status.flags |= CC_NOT_NEGATIVE; | |
437 | return AS2 (test%B0,%1,%b0); | |
438 | } | |
886c62d1 | 439 | |
b4ac57ab | 440 | if ((INTVAL (operands[1]) & ~0xff00) == 0) |
886c62d1 | 441 | { |
b4ac57ab | 442 | cc_status.flags |= CC_NOT_NEGATIVE; |
886c62d1 JVA |
443 | operands[1] = gen_rtx (CONST_INT, VOIDmode, |
444 | INTVAL (operands[1]) >> 8); | |
b4ac57ab RS |
445 | |
446 | if (QI_REG_P (operands[0])) | |
447 | return AS2 (test%B0,%1,%h0); | |
448 | else | |
449 | { | |
450 | operands[0] = adj_offsettable_operand (operands[0], 1); | |
451 | return AS2 (test%B0,%1,%b0); | |
452 | } | |
453 | } | |
454 | ||
455 | if (GET_CODE (operands[0]) == MEM | |
456 | && (INTVAL (operands[1]) & ~0xff0000) == 0) | |
457 | { | |
458 | cc_status.flags |= CC_NOT_NEGATIVE; | |
459 | operands[1] = gen_rtx (CONST_INT, VOIDmode, | |
460 | INTVAL (operands[1]) >> 16); | |
461 | ||
462 | operands[0] = adj_offsettable_operand (operands[0], 2); | |
463 | return AS2 (test%B0,%1,%b0); | |
464 | } | |
465 | ||
466 | if (GET_CODE (operands[0]) == MEM | |
467 | && (INTVAL (operands[1]) & ~0xff000000) == 0) | |
468 | { | |
469 | operands[1] = gen_rtx (CONST_INT, VOIDmode, | |
470 | (INTVAL (operands[1]) >> 24) & 0xff); | |
471 | ||
472 | operands[0] = adj_offsettable_operand (operands[0], 3); | |
473 | return AS2 (test%B0,%1,%b0); | |
886c62d1 JVA |
474 | } |
475 | } | |
476 | ||
477 | if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) | |
478 | return AS2 (test%L0,%1,%0); | |
479 | ||
480 | return AS2 (test%L1,%0,%1); | |
481 | }") | |
482 | ||
483 | (define_insn "" | |
484 | [(set (cc0) | |
b4ac57ab | 485 | (and:HI (match_operand:HI 0 "general_operand" "%ro") |
886c62d1 JVA |
486 | (match_operand:HI 1 "general_operand" "ri")))] |
487 | "" | |
488 | "* | |
489 | { | |
490 | if (GET_CODE (operands[1]) == CONST_INT | |
b4ac57ab RS |
491 | && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) |
492 | && ! NON_QI_REG_P (operands[0])) | |
886c62d1 | 493 | { |
b4ac57ab | 494 | if ((INTVAL (operands[1]) & 0xff00) == 0) |
886c62d1 | 495 | { |
b4ac57ab | 496 | /* ??? This might not be necessary. */ |
886c62d1 JVA |
497 | if (INTVAL (operands[1]) & 0xffff0000) |
498 | operands[1] = gen_rtx (CONST_INT, VOIDmode, | |
499 | INTVAL (operands[1]) & 0xff); | |
500 | ||
501 | /* We may set the sign bit spuriously. */ | |
502 | cc_status.flags |= CC_NOT_NEGATIVE; | |
503 | return AS2 (test%B0,%1,%b0); | |
504 | } | |
505 | ||
b4ac57ab | 506 | if ((INTVAL (operands[1]) & 0xff) == 0) |
886c62d1 JVA |
507 | { |
508 | operands[1] = gen_rtx (CONST_INT, VOIDmode, | |
509 | (INTVAL (operands[1]) >> 8) & 0xff); | |
b4ac57ab RS |
510 | |
511 | if (QI_REG_P (operands[0])) | |
512 | return AS2 (test%B0,%1,%h0); | |
513 | else | |
514 | { | |
515 | operands[0] = adj_offsettable_operand (operands[0], 1); | |
516 | return AS2 (test%B0,%1,%b0); | |
517 | } | |
886c62d1 JVA |
518 | } |
519 | } | |
520 | ||
521 | if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) | |
522 | return AS2 (test%W0,%1,%0); | |
523 | ||
524 | return AS2 (test%W1,%0,%1); | |
525 | }") | |
526 | ||
527 | (define_insn "" | |
528 | [(set (cc0) | |
529 | (and:QI (match_operand:QI 0 "general_operand" "%qm") | |
530 | (match_operand:QI 1 "general_operand" "qi")))] | |
531 | "" | |
532 | "* | |
533 | { | |
534 | if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) | |
535 | return AS2 (test%B0,%1,%0); | |
536 | ||
537 | return AS2 (test%B1,%0,%1); | |
538 | }") | |
539 | \f | |
540 | ;; move instructions. | |
541 | ;; There is one for each machine mode, | |
542 | ;; and each is preceded by a corresponding push-insn pattern | |
543 | ;; (since pushes are not general_operands on the 386). | |
544 | ||
545 | (define_insn "" | |
546 | [(set (match_operand:SI 0 "push_operand" "=<") | |
547 | (match_operand:SI 1 "general_operand" "g"))] | |
548 | "! TARGET_486" | |
549 | "push%L0 %1") | |
550 | ||
551 | ;; On a 486, it is faster to move MEM to a REG and then push, rather than | |
552 | ;; push MEM directly. | |
553 | ||
554 | (define_insn "" | |
555 | [(set (match_operand:SI 0 "push_operand" "=<") | |
556 | (match_operand:SI 1 "general_operand" "ri"))] | |
557 | "TARGET_486" | |
558 | "push%L0 %1") | |
559 | ||
560 | ;; General case of fullword move. | |
561 | ||
2bb7a0f5 RS |
562 | ;; If generating PIC code and operands[1] is a symbolic CONST, emit a |
563 | ;; move to get the address of the symbolic object from the GOT. | |
564 | ||
565 | (define_expand "movsi" | |
566 | [(set (match_operand:SI 0 "general_operand" "") | |
567 | (match_operand:SI 1 "general_operand" ""))] | |
568 | "" | |
569 | " | |
570 | { | |
571 | extern int flag_pic; | |
572 | ||
573 | if (flag_pic && SYMBOLIC_CONST (operands[1])) | |
574 | emit_pic_move (operands, SImode); | |
575 | }") | |
576 | ||
886c62d1 JVA |
577 | ;; On i486, incl reg is faster than movl $1,reg. |
578 | ||
2bb7a0f5 | 579 | (define_insn "" |
886c62d1 JVA |
580 | [(set (match_operand:SI 0 "general_operand" "=g,r") |
581 | (match_operand:SI 1 "general_operand" "ri,m"))] | |
582 | "" | |
583 | "* | |
584 | { | |
585 | rtx link; | |
586 | if (operands[1] == const0_rtx && REG_P (operands[0])) | |
587 | return AS2 (xor%L0,%0,%0); | |
588 | ||
589 | if (operands[1] == const1_rtx | |
590 | && (link = find_reg_note (insn, REG_WAS_0, 0)) | |
591 | /* Make sure the insn that stored the 0 is still present. */ | |
592 | && ! XEXP (link, 0)->volatil | |
593 | && GET_CODE (XEXP (link, 0)) != NOTE | |
594 | /* Make sure cross jumping didn't happen here. */ | |
595 | && no_labels_between_p (XEXP (link, 0), insn)) | |
596 | /* Fastest way to change a 0 to a 1. */ | |
597 | return AS1 (inc%L0,%0); | |
598 | ||
599 | return AS2 (mov%L0,%1,%0); | |
600 | }") | |
601 | ||
602 | (define_insn "" | |
603 | [(set (match_operand:HI 0 "push_operand" "=<") | |
604 | (match_operand:HI 1 "general_operand" "g"))] | |
605 | "" | |
606 | "push%W0 %1") | |
607 | ||
608 | ;; On i486, an incl and movl are both faster than incw and movw. | |
609 | ||
610 | (define_insn "movhi" | |
611 | [(set (match_operand:HI 0 "general_operand" "=g,r") | |
612 | (match_operand:HI 1 "general_operand" "ri,m"))] | |
613 | "" | |
614 | "* | |
615 | { | |
616 | rtx link; | |
617 | if (REG_P (operands[0]) && operands[1] == const0_rtx) | |
618 | return AS2 (xor%L0,%k0,%k0); | |
619 | ||
620 | if (REG_P (operands[0]) && operands[1] == const1_rtx | |
621 | && (link = find_reg_note (insn, REG_WAS_0, 0)) | |
622 | /* Make sure the insn that stored the 0 is still present. */ | |
623 | && ! XEXP (link, 0)->volatil | |
624 | && GET_CODE (XEXP (link, 0)) != NOTE | |
625 | /* Make sure cross jumping didn't happen here. */ | |
626 | && no_labels_between_p (XEXP (link, 0), insn)) | |
627 | /* Fastest way to change a 0 to a 1. */ | |
628 | return AS1 (inc%L0,%k0); | |
629 | ||
630 | if (REG_P (operands[0])) | |
631 | { | |
632 | if (REG_P (operands[1])) | |
633 | return AS2 (mov%L0,%k1,%k0); | |
634 | else if (CONSTANT_P (operands[1])) | |
635 | return AS2 (mov%L0,%1,%k0); | |
636 | } | |
637 | ||
638 | return AS2 (mov%W0,%1,%0); | |
639 | }") | |
640 | ||
641 | (define_insn "movstricthi" | |
642 | [(set (strict_low_part (match_operand:HI 0 "general_operand" "+g,r")) | |
643 | (match_operand:HI 1 "general_operand" "ri,m"))] | |
644 | "" | |
645 | "* | |
646 | { | |
647 | rtx link; | |
648 | if (operands[1] == const0_rtx && REG_P (operands[0])) | |
649 | return AS2 (xor%W0,%0,%0); | |
650 | ||
651 | if (operands[1] == const1_rtx | |
652 | && (link = find_reg_note (insn, REG_WAS_0, 0)) | |
653 | /* Make sure the insn that stored the 0 is still present. */ | |
654 | && ! XEXP (link, 0)->volatil | |
655 | && GET_CODE (XEXP (link, 0)) != NOTE | |
656 | /* Make sure cross jumping didn't happen here. */ | |
657 | && no_labels_between_p (XEXP (link, 0), insn)) | |
658 | /* Fastest way to change a 0 to a 1. */ | |
659 | return AS1 (inc%W0,%0); | |
660 | ||
661 | return AS2 (mov%W0,%1,%0); | |
662 | }") | |
663 | ||
664 | ;; emit_push_insn when it calls move_by_pieces | |
665 | ;; requires an insn to "push a byte". | |
666 | ;; But actually we use pushw, which has the effect of rounding | |
667 | ;; the amount pushed up to a halfword. | |
668 | (define_insn "" | |
669 | [(set (match_operand:QI 0 "push_operand" "=<") | |
670 | (match_operand:QI 1 "general_operand" "q"))] | |
671 | "" | |
672 | "* | |
673 | { | |
674 | operands[1] = gen_rtx (REG, HImode, REGNO (operands[1])); | |
675 | return AS1 (push%W0,%1); | |
676 | }") | |
677 | ||
678 | ;; On i486, incb reg is faster than movb $1,reg. | |
679 | ||
680 | ;; ??? Do a recognizer for zero_extract that looks just like this, but reads | |
681 | ;; or writes %ah, %bh, %ch, %dh. | |
682 | ||
683 | (define_insn "movqi" | |
684 | [(set (match_operand:QI 0 "general_operand" "=q,*r,qm") | |
685 | (match_operand:QI 1 "general_operand" "*g,q,qn"))] | |
686 | "" | |
687 | "* | |
688 | { | |
689 | rtx link; | |
690 | if (operands[1] == const0_rtx && REG_P (operands[0])) | |
691 | return AS2 (xor%B0,%0,%0); | |
692 | ||
693 | if (operands[1] == const1_rtx | |
694 | && (link = find_reg_note (insn, REG_WAS_0, 0)) | |
695 | /* Make sure the insn that stored the 0 is still present. */ | |
696 | && ! XEXP (link, 0)->volatil | |
697 | && GET_CODE (XEXP (link, 0)) != NOTE | |
698 | /* Make sure cross jumping didn't happen here. */ | |
699 | && no_labels_between_p (XEXP (link, 0), insn)) | |
700 | /* Fastest way to change a 0 to a 1. */ | |
701 | return AS1 (inc%B0,%0); | |
702 | ||
703 | /* If mov%B0 isn't allowed for one of these regs, use mov%L0. */ | |
704 | if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1])) | |
705 | return (AS2 (mov%L0,%k1,%k0)); | |
706 | ||
707 | return (AS2 (mov%B0,%1,%0)); | |
708 | }") | |
709 | ||
710 | ;; If it becomes necessary to support movstrictqi into %esi or %edi, | |
711 | ;; use the insn sequence: | |
712 | ;; | |
713 | ;; shrdl $8,srcreg,dstreg | |
714 | ;; rorl $24,dstreg | |
715 | ;; | |
716 | ;; If operands[1] is a constant, then an andl/orl sequence would be | |
717 | ;; faster. | |
718 | ||
719 | (define_insn "movstrictqi" | |
720 | [(set (strict_low_part (match_operand:QI 0 "general_operand" "+q,qm")) | |
721 | (match_operand:QI 1 "general_operand" "*g,qn"))] | |
722 | "" | |
723 | "* | |
724 | { | |
725 | rtx link; | |
726 | if (operands[1] == const0_rtx && REG_P (operands[0])) | |
727 | return AS2 (xor%B0,%0,%0); | |
728 | ||
729 | if (operands[1] == const1_rtx | |
730 | && (link = find_reg_note (insn, REG_WAS_0, 0)) | |
731 | /* Make sure the insn that stored the 0 is still present. */ | |
732 | && ! XEXP (link, 0)->volatil | |
733 | && GET_CODE (XEXP (link, 0)) != NOTE | |
734 | /* Make sure cross jumping didn't happen here. */ | |
735 | && no_labels_between_p (XEXP (link, 0), insn)) | |
736 | /* Fastest way to change a 0 to a 1. */ | |
737 | return AS1 (inc%B0,%0); | |
738 | ||
739 | /* If mov%B0 isn't allowed for one of these regs, use mov%W0. */ | |
740 | if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1])) | |
741 | { | |
742 | abort (); | |
743 | return (AS2 (mov%L0,%k1,%k0)); | |
744 | } | |
745 | ||
746 | return AS2 (mov%B0,%1,%0); | |
747 | }") | |
748 | ||
749 | (define_insn "" | |
750 | [(set (match_operand:SF 0 "push_operand" "=<,<") | |
751 | (match_operand:SF 1 "general_operand" "gF,f"))] | |
752 | "" | |
753 | "* | |
754 | { | |
755 | if (STACK_REG_P (operands[1])) | |
756 | { | |
757 | rtx xops[3]; | |
758 | ||
759 | if (! STACK_TOP_P (operands[1])) | |
760 | abort (); | |
761 | ||
762 | xops[0] = AT_SP (SFmode); | |
763 | xops[1] = gen_rtx (CONST_INT, VOIDmode, 4); | |
764 | xops[2] = stack_pointer_rtx; | |
765 | ||
766 | output_asm_insn (AS2 (sub%L2,%1,%2), xops); | |
767 | ||
768 | if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) | |
769 | output_asm_insn (AS1 (fstp%S0,%0), xops); | |
770 | else | |
771 | output_asm_insn (AS1 (fst%S0,%0), xops); | |
772 | RET; | |
773 | } | |
774 | return AS1 (push%L1,%1); | |
775 | }") | |
776 | ||
777 | (define_insn "movsf" | |
778 | [(set (match_operand:SF 0 "general_operand" "=f,fm,!*rf,!*rm") | |
779 | (match_operand:SF 1 "general_operand" "fmG,f,*rfm,*rfF"))] | |
780 | "" | |
781 | "* | |
782 | { | |
783 | int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; | |
784 | ||
785 | /* First handle a `pop' insn or a `fld %st(0)' */ | |
786 | ||
787 | if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1])) | |
788 | { | |
789 | if (stack_top_dies) | |
790 | return AS1 (fstp,%y0); | |
791 | else | |
792 | return AS1 (fld,%y0); | |
793 | } | |
794 | ||
795 | /* Handle a transfer between the 387 and a 386 register */ | |
796 | ||
797 | if (STACK_TOP_P (operands[0]) && NON_STACK_REG_P (operands[1])) | |
798 | { | |
799 | output_op_from_reg (operands[1], AS1 (fld%z0,%y1)); | |
800 | RET; | |
801 | } | |
802 | ||
803 | if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0])) | |
804 | { | |
805 | output_to_reg (operands[0], stack_top_dies); | |
806 | RET; | |
807 | } | |
808 | ||
809 | /* Handle other kinds of writes from the 387 */ | |
810 | ||
811 | if (STACK_TOP_P (operands[1])) | |
812 | { | |
813 | if (stack_top_dies) | |
814 | return AS1 (fstp%z0,%y0); | |
815 | else | |
816 | return AS1 (fst%z0,%y0); | |
817 | } | |
818 | ||
819 | /* Handle other kinds of reads to the 387 */ | |
820 | ||
821 | if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE) | |
822 | return (char *) output_move_const_single (operands); | |
823 | ||
824 | if (STACK_TOP_P (operands[0])) | |
825 | return AS1 (fld%z1,%y1); | |
826 | ||
827 | /* Handle all SFmode moves not involving the 387 */ | |
828 | ||
829 | return (char *) singlemove_string (operands); | |
830 | }") | |
831 | ||
832 | ;;should change to handle the memory operands[1] without doing df push.. | |
833 | (define_insn "" | |
834 | [(set (match_operand:DF 0 "push_operand" "=<,<") | |
835 | (match_operand:DF 1 "general_operand" "gF,f"))] | |
836 | "" | |
837 | "* | |
838 | { | |
839 | if (STACK_REG_P (operands[1])) | |
840 | { | |
841 | rtx xops[3]; | |
842 | ||
843 | xops[0] = AT_SP (SFmode); | |
844 | xops[1] = gen_rtx (CONST_INT, VOIDmode, 8); | |
845 | xops[2] = stack_pointer_rtx; | |
846 | ||
847 | output_asm_insn (AS2 (sub%L2,%1,%2), xops); | |
848 | ||
849 | if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) | |
850 | output_asm_insn (AS1 (fstp%Q0,%0), xops); | |
851 | else | |
852 | output_asm_insn (AS1 (fst%Q0,%0), xops); | |
853 | ||
854 | RET; | |
855 | } | |
856 | else | |
857 | return (char *) output_move_double (operands); | |
858 | }") | |
859 | ||
860 | (define_insn "swapdf" | |
861 | [(set (match_operand:DF 0 "register_operand" "f") | |
862 | (match_operand:DF 1 "register_operand" "f")) | |
863 | (set (match_dup 1) | |
864 | (match_dup 0))] | |
865 | "" | |
866 | "* | |
867 | { | |
868 | if (STACK_TOP_P (operands[0])) | |
869 | return AS1 (fxch,%1); | |
870 | else | |
871 | return AS1 (fxch,%0); | |
872 | }") | |
873 | ||
874 | (define_insn "movdf" | |
875 | [(set (match_operand:DF 0 "general_operand" "=f,fm,!*rf,!*rm") | |
876 | (match_operand:DF 1 "general_operand" "fmG,f,*rfm,*rfF"))] | |
877 | "" | |
878 | "* | |
879 | { | |
880 | int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; | |
881 | ||
882 | /* First handle a `pop' insn or a `fld %st(0)' */ | |
883 | ||
884 | if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1])) | |
885 | { | |
886 | if (stack_top_dies) | |
887 | return AS1 (fstp,%y0); | |
888 | else | |
889 | return AS1 (fld,%y0); | |
890 | } | |
891 | ||
892 | /* Handle a transfer between the 387 and a 386 register */ | |
893 | ||
894 | if (STACK_TOP_P (operands[0]) && NON_STACK_REG_P (operands[1])) | |
895 | { | |
896 | output_op_from_reg (operands[1], AS1 (fld%z0,%y1)); | |
897 | RET; | |
898 | } | |
899 | ||
900 | if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0])) | |
901 | { | |
902 | output_to_reg (operands[0], stack_top_dies); | |
903 | RET; | |
904 | } | |
905 | ||
906 | /* Handle other kinds of writes from the 387 */ | |
907 | ||
908 | if (STACK_TOP_P (operands[1])) | |
909 | { | |
910 | if (stack_top_dies) | |
911 | return AS1 (fstp%z0,%y0); | |
912 | else | |
913 | return AS1 (fst%z0,%y0); | |
914 | } | |
915 | ||
916 | /* Handle other kinds of reads to the 387 */ | |
917 | ||
918 | if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE) | |
919 | return (char *) output_move_const_single (operands); | |
920 | ||
921 | if (STACK_TOP_P (operands[0])) | |
922 | return AS1 (fld%z1,%y1); | |
923 | ||
924 | /* Handle all DFmode moves not involving the 387 */ | |
925 | ||
926 | return (char *) output_move_double (operands); | |
927 | }") | |
928 | ||
929 | (define_insn "" | |
930 | [(set (match_operand:DI 0 "push_operand" "=<") | |
931 | (match_operand:DI 1 "general_operand" "roiF"))] | |
932 | "" | |
933 | "* | |
934 | { | |
935 | return (char *) output_move_double (operands); | |
936 | }") | |
937 | ||
938 | (define_insn "movdi" | |
939 | [(set (match_operand:DI 0 "general_operand" "=&r,rm") | |
940 | (match_operand:DI 1 "general_operand" "m,riF"))] | |
941 | "" | |
942 | "* | |
943 | { | |
944 | return (char *) output_move_double (operands); | |
945 | }") | |
946 | \f | |
947 | ;;- conversion instructions | |
948 | ;;- NONE | |
949 | ||
886c62d1 JVA |
950 | ;;- zero extension instructions |
951 | ;; See comments by `andsi' for when andl is faster than movzx. | |
952 | ||
953 | (define_insn "zero_extendhisi2" | |
954 | [(set (match_operand:SI 0 "general_operand" "=r") | |
955 | (zero_extend:SI | |
956 | (match_operand:HI 1 "nonimmediate_operand" "rm")))] | |
957 | "" | |
958 | "* | |
959 | { | |
960 | if ((TARGET_486 || REGNO (operands[0]) == 0) | |
961 | && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1])) | |
962 | { | |
963 | rtx xops[2]; | |
964 | xops[0] = operands[0]; | |
965 | xops[1] = gen_rtx (CONST_INT, VOIDmode, 0xffff); | |
966 | output_asm_insn (AS2 (and%L0,%1,%k0), xops); | |
967 | RET; | |
968 | } | |
969 | ||
970 | #ifdef INTEL_SYNTAX | |
971 | return AS2 (movzx,%1,%0); | |
972 | #else | |
973 | return AS2 (movz%W0%L0,%1,%0); | |
974 | #endif | |
975 | }") | |
976 | ||
977 | (define_insn "zero_extendqihi2" | |
978 | [(set (match_operand:HI 0 "general_operand" "=r") | |
979 | (zero_extend:HI | |
980 | (match_operand:QI 1 "nonimmediate_operand" "qm")))] | |
981 | "" | |
982 | "* | |
983 | { | |
984 | if ((TARGET_486 || REGNO (operands[0]) == 0) | |
985 | && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1])) | |
986 | { | |
987 | rtx xops[2]; | |
988 | xops[0] = operands[0]; | |
989 | xops[1] = gen_rtx (CONST_INT, VOIDmode, 0xff); | |
990 | output_asm_insn (AS2 (and%L0,%1,%k0), xops); | |
991 | RET; | |
992 | } | |
993 | ||
994 | #ifdef INTEL_SYNTAX | |
995 | return AS2 (movzx,%1,%0); | |
996 | #else | |
997 | return AS2 (movz%B0%W0,%1,%0); | |
998 | #endif | |
999 | }") | |
1000 | ||
1001 | (define_insn "zero_extendqisi2" | |
1002 | [(set (match_operand:SI 0 "general_operand" "=r") | |
1003 | (zero_extend:SI | |
1004 | (match_operand:QI 1 "nonimmediate_operand" "qm")))] | |
1005 | "" | |
1006 | "* | |
1007 | { | |
1008 | if ((TARGET_486 || REGNO (operands[0]) == 0) | |
1009 | && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1])) | |
1010 | { | |
1011 | rtx xops[2]; | |
1012 | xops[0] = operands[0]; | |
1013 | xops[1] = gen_rtx (CONST_INT, VOIDmode, 0xff); | |
1014 | output_asm_insn (AS2 (and%L0,%1,%k0), xops); | |
1015 | RET; | |
1016 | } | |
1017 | ||
1018 | #ifdef INTEL_SYNTAX | |
1019 | return AS2 (movzx,%1,%0); | |
1020 | #else | |
1021 | return AS2 (movz%B0%L0,%1,%0); | |
1022 | #endif | |
1023 | }") | |
1024 | \f | |
1025 | ;;- sign extension instructions | |
1026 | ||
1027 | /* | |
1028 | (define_insn "extendsidi2" | |
1029 | [(set (match_operand:DI 0 "general_operand" "=a") | |
1030 | (sign_extend:DI | |
1031 | (match_operand:SI 1 "nonimmediate_operand" "a")))] | |
1032 | "" | |
1033 | "clq") | |
1034 | */ | |
1035 | ||
1036 | ;; Note that the i386 programmers' manual says that the opcodes | |
1037 | ;; are named movsx..., but the assembler on Unix does not accept that. | |
1038 | ;; We use what the Unix assembler expects. | |
1039 | ||
1040 | (define_insn "extendhisi2" | |
1041 | [(set (match_operand:SI 0 "general_operand" "=r") | |
1042 | (sign_extend:SI | |
1043 | (match_operand:HI 1 "nonimmediate_operand" "rm")))] | |
1044 | "" | |
1045 | "* | |
1046 | { | |
1047 | if (REGNO (operands[0]) == 0 | |
1048 | && REG_P (operands[1]) && REGNO (operands[1]) == 0) | |
1049 | #ifdef INTEL_SYNTAX | |
1050 | return \"cwde\"; | |
1051 | #else | |
1052 | return \"cwtl\"; | |
1053 | #endif | |
1054 | ||
1055 | #ifdef INTEL_SYNTAX | |
1056 | return AS2 (movsx,%1,%0); | |
1057 | #else | |
1058 | return AS2 (movs%W0%L0,%1,%0); | |
1059 | #endif | |
1060 | }") | |
1061 | ||
1062 | (define_insn "extendqihi2" | |
1063 | [(set (match_operand:HI 0 "general_operand" "=r") | |
1064 | (sign_extend:HI | |
1065 | (match_operand:QI 1 "nonimmediate_operand" "qm")))] | |
1066 | "" | |
1067 | "* | |
1068 | { | |
1069 | if (REGNO (operands[0]) == 0 | |
1070 | && REG_P (operands[1]) && REGNO (operands[1]) == 0) | |
1071 | return \"cbtw\"; | |
1072 | ||
1073 | #ifdef INTEL_SYNTAX | |
1074 | return AS2 (movsx,%1,%0); | |
1075 | #else | |
1076 | return AS2 (movs%B0%W0,%1,%0); | |
1077 | #endif | |
1078 | }") | |
1079 | ||
1080 | (define_insn "extendqisi2" | |
1081 | [(set (match_operand:SI 0 "general_operand" "=r") | |
1082 | (sign_extend:SI | |
1083 | (match_operand:QI 1 "nonimmediate_operand" "qm")))] | |
1084 | "" | |
1085 | "* | |
1086 | { | |
1087 | #ifdef INTEL_SYNTAX | |
1088 | return AS2 (movsx,%1,%0); | |
1089 | #else | |
1090 | return AS2 (movs%B0%L0,%1,%0); | |
1091 | #endif | |
1092 | }") | |
1093 | \f | |
1094 | ;; Conversions between float and double. | |
1095 | ||
1096 | (define_insn "extendsfdf2" | |
1097 | [(set (match_operand:DF 0 "general_operand" "=fm,f,f,!*r") | |
1098 | (float_extend:DF | |
1099 | (match_operand:SF 1 "general_operand" "f,fm,!*r,f")))] | |
1100 | "TARGET_80387" | |
1101 | "* | |
1102 | { | |
1103 | int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; | |
1104 | ||
1105 | if (NON_STACK_REG_P (operands[1])) | |
1106 | { | |
1107 | output_op_from_reg (operands[1], AS1 (fld%z0,%y1)); | |
1108 | RET; | |
1109 | } | |
1110 | ||
1111 | if (NON_STACK_REG_P (operands[0])) | |
1112 | { | |
1113 | output_to_reg (operands[0], stack_top_dies); | |
1114 | RET; | |
1115 | } | |
1116 | ||
1117 | if (STACK_TOP_P (operands[0])) | |
1118 | return AS1 (fld%z1,%y1); | |
1119 | ||
1120 | if (GET_CODE (operands[0]) == MEM) | |
1121 | { | |
1122 | if (stack_top_dies) | |
1123 | return AS1 (fstp%z0,%y0); | |
1124 | else | |
1125 | return AS1 (fst%z0,%y0); | |
1126 | } | |
1127 | ||
1128 | abort (); | |
1129 | }") | |
1130 | ||
1131 | ;; This cannot output into an f-reg because there is no way to be sure | |
1132 | ;; of truncating in that case. Otherwise this is just like a simple move | |
1133 | ;; insn. | |
1134 | ||
1135 | (define_insn "truncdfsf2" | |
1136 | [(set (match_operand:SF 0 "general_operand" "=m,!*r") | |
1137 | (float_truncate:SF | |
1138 | (match_operand:DF 1 "register_operand" "f,f")))] | |
1139 | "TARGET_80387" | |
1140 | "* | |
1141 | { | |
1142 | int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; | |
1143 | ||
1144 | if (NON_STACK_REG_P (operands[0])) | |
1145 | { | |
1146 | output_to_reg (operands[0], stack_top_dies); | |
1147 | RET; | |
1148 | } | |
1149 | else if (GET_CODE (operands[0]) == MEM) | |
1150 | { | |
1151 | if (stack_top_dies) | |
1152 | return AS1 (fstp%z0,%0); | |
1153 | else | |
1154 | return AS1 (fst%z0,%0); | |
1155 | } | |
1156 | else | |
1157 | abort (); | |
1158 | }") | |
1159 | \f | |
1160 | ;; The 387 requires that the stack top dies after converting to DImode. | |
1161 | ||
1162 | ;; Represent an unsigned conversion from SImode to MODE_FLOAT by first | |
1163 | ;; doing a signed conversion to DImode, and then taking just the low | |
1164 | ;; part. | |
1165 | ||
1166 | (define_expand "fixuns_truncdfsi2" | |
5203427b JVA |
1167 | [(set (match_dup 5) |
1168 | (match_operand:DF 1 "register_operand" "")) | |
1169 | (parallel [(set (match_dup 3) | |
1170 | (fix:DI (fix:DF (match_dup 5)))) | |
886c62d1 | 1171 | (clobber (match_scratch:HI 2 "")) |
5203427b | 1172 | (clobber (match_dup 5))]) |
886c62d1 JVA |
1173 | (set (match_operand:SI 0 "general_operand" "") |
1174 | (match_dup 4))] | |
1175 | "TARGET_80387" | |
1176 | " | |
1177 | { | |
1178 | operands[3] = gen_reg_rtx (DImode); | |
1179 | operands[4] = gen_lowpart (SImode, operands[3]); | |
5203427b | 1180 | operands[5] = gen_reg_rtx (DFmode); |
886c62d1 JVA |
1181 | }") |
1182 | ||
1183 | (define_expand "fixuns_truncsfsi2" | |
5203427b JVA |
1184 | [(set (match_dup 5) |
1185 | (match_operand:SF 1 "register_operand" "")) | |
1186 | (parallel [(set (match_dup 3) | |
1187 | (fix:DI (fix:SF (match_dup 5)))) | |
886c62d1 | 1188 | (clobber (match_scratch:HI 2 "")) |
5203427b | 1189 | (clobber (match_dup 5))]) |
886c62d1 JVA |
1190 | (set (match_operand:SI 0 "general_operand" "") |
1191 | (match_dup 4))] | |
1192 | "TARGET_80387" | |
1193 | " | |
1194 | { | |
1195 | operands[3] = gen_reg_rtx (DImode); | |
1196 | operands[4] = gen_lowpart (SImode, operands[3]); | |
5203427b | 1197 | operands[5] = gen_reg_rtx (SFmode); |
886c62d1 JVA |
1198 | }") |
1199 | ||
1200 | ;; Signed conversion to DImode. | |
1201 | ||
1202 | (define_expand "fix_truncdfdi2" | |
5203427b JVA |
1203 | [(set (match_dup 3) |
1204 | (match_operand:DF 1 "register_operand" "")) | |
1205 | (parallel [(set (match_operand:DI 0 "general_operand" "") | |
1206 | (fix:DI (fix:DF (match_dup 3)))) | |
886c62d1 | 1207 | (clobber (match_scratch:HI 2 "")) |
5203427b | 1208 | (clobber (match_dup 3))])] |
886c62d1 JVA |
1209 | "TARGET_80387" |
1210 | " | |
1211 | { | |
1212 | operands[1] = copy_to_mode_reg (DFmode, operands[1]); | |
5203427b | 1213 | operands[3] = gen_reg_rtx (DFmode); |
886c62d1 JVA |
1214 | }") |
1215 | ||
1216 | (define_expand "fix_truncsfdi2" | |
5203427b JVA |
1217 | [(set (match_dup 3) |
1218 | (match_operand:SF 1 "register_operand" "")) | |
1219 | (parallel [(set (match_operand:DI 0 "general_operand" "") | |
1220 | (fix:DI (fix:SF (match_dup 3)))) | |
886c62d1 | 1221 | (clobber (match_scratch:HI 2 "")) |
5203427b | 1222 | (clobber (match_dup 3))])] |
886c62d1 JVA |
1223 | "TARGET_80387" |
1224 | " | |
1225 | { | |
1226 | operands[1] = copy_to_mode_reg (SFmode, operands[1]); | |
5203427b | 1227 | operands[3] = gen_reg_rtx (SFmode); |
886c62d1 JVA |
1228 | }") |
1229 | ||
b4ac57ab | 1230 | ;; These match a signed conversion of either DFmode or SFmode to DImode. |
886c62d1 JVA |
1231 | |
1232 | (define_insn "" | |
1233 | [(set (match_operand:DI 0 "general_operand" "=m,!*r") | |
1234 | (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f,f")))) | |
1235 | (clobber (match_scratch:HI 2 "=&r,&r")) | |
1236 | (clobber (match_dup 1))] | |
1237 | "TARGET_80387" | |
1238 | "* return (char *) output_fix_trunc (insn, operands);") | |
1239 | ||
1240 | (define_insn "" | |
1241 | [(set (match_operand:DI 0 "general_operand" "=m,!*r") | |
1242 | (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f,f")))) | |
1243 | (clobber (match_scratch:HI 2 "=&r,&r")) | |
1244 | (clobber (match_dup 1))] | |
1245 | "TARGET_80387" | |
1246 | "* return (char *) output_fix_trunc (insn, operands);") | |
1247 | ||
1248 | ;; Signed MODE_FLOAT conversion to SImode. | |
1249 | ||
1250 | (define_expand "fix_truncdfsi2" | |
1251 | [(parallel [(set (match_operand:SI 0 "general_operand" "") | |
1252 | (fix:SI | |
1253 | (fix:DF (match_operand:DF 1 "register_operand" "")))) | |
1254 | (clobber (match_scratch:HI 2 ""))])] | |
1255 | "TARGET_80387" | |
1256 | "") | |
1257 | ||
1258 | (define_expand "fix_truncsfsi2" | |
1259 | [(parallel [(set (match_operand:SI 0 "general_operand" "") | |
1260 | (fix:SI | |
1261 | (fix:SF (match_operand:SF 1 "register_operand" "")))) | |
1262 | (clobber (match_scratch:HI 2 ""))])] | |
1263 | "TARGET_80387" | |
1264 | "") | |
1265 | ||
1266 | (define_insn "" | |
1267 | [(set (match_operand:SI 0 "general_operand" "=m,!*r") | |
1268 | (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f,f")))) | |
1269 | (clobber (match_scratch:HI 2 "=&r,&r"))] | |
1270 | "TARGET_80387" | |
1271 | "* return (char *) output_fix_trunc (insn, operands);") | |
1272 | ||
1273 | (define_insn "" | |
1274 | [(set (match_operand:SI 0 "general_operand" "=m,!*r") | |
1275 | (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f,f")))) | |
1276 | (clobber (match_scratch:HI 2 "=&r,&r"))] | |
1277 | "TARGET_80387" | |
1278 | "* return (char *) output_fix_trunc (insn, operands);") | |
1279 | \f | |
1280 | ;; Conversion between fixed point and floating point. | |
1281 | ;; The actual pattern that matches these is at the end of this file. | |
1282 | ||
b4ac57ab | 1283 | ;; ??? Possibly represent floatunssidf2 here in gcc2. |
886c62d1 JVA |
1284 | |
1285 | (define_expand "floatsisf2" | |
1286 | [(set (match_operand:SF 0 "register_operand" "") | |
1287 | (float:SF (match_operand:SI 1 "general_operand" "")))] | |
1288 | "TARGET_80387" | |
1289 | "") | |
1290 | ||
1291 | (define_expand "floatdisf2" | |
1292 | [(set (match_operand:SF 0 "register_operand" "") | |
1293 | (float:SF (match_operand:DI 1 "general_operand" "")))] | |
1294 | "TARGET_80387" | |
1295 | "") | |
1296 | ||
1297 | (define_expand "floatsidf2" | |
1298 | [(set (match_operand:DF 0 "register_operand" "") | |
1299 | (float:DF (match_operand:SI 1 "general_operand" "")))] | |
1300 | "TARGET_80387" | |
1301 | "") | |
1302 | ||
1303 | (define_expand "floatdidf2" | |
1304 | [(set (match_operand:DF 0 "register_operand" "") | |
1305 | (float:DF (match_operand:DI 1 "general_operand" "")))] | |
1306 | "TARGET_80387" | |
1307 | "") | |
1308 | ||
1309 | ;; This will convert from SImode or DImode to MODE_FLOAT. | |
1310 | ||
1311 | (define_insn "" | |
1312 | [(set (match_operand 0 "register_operand" "=f,f") | |
1313 | (match_operator 2 "float_op" | |
1314 | [(match_operand:DI 1 "general_operand" "m,!*r")]))] | |
1315 | "TARGET_80387 && GET_MODE (operands[0]) == GET_MODE (operands[2]) | |
1316 | && GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_FLOAT" | |
1317 | "* | |
1318 | { | |
1319 | if (NON_STACK_REG_P (operands[1])) | |
1320 | { | |
1321 | output_op_from_reg (operands[1], AS1 (fild%z0,%1)); | |
1322 | RET; | |
1323 | } | |
1324 | else if (GET_CODE (operands[1]) == MEM) | |
1325 | return AS1 (fild%z1,%1); | |
1326 | else | |
1327 | abort (); | |
1328 | }") | |
1329 | ||
1330 | (define_insn "" | |
1331 | [(set (match_operand 0 "register_operand" "=f,f") | |
1332 | (match_operator 2 "float_op" | |
1333 | [(match_operand:SI 1 "general_operand" "m,!*r")]))] | |
1334 | "TARGET_80387 && GET_MODE (operands[0]) == GET_MODE (operands[2]) | |
1335 | && GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_FLOAT" | |
1336 | "* | |
1337 | { | |
1338 | if (NON_STACK_REG_P (operands[1])) | |
1339 | { | |
1340 | output_op_from_reg (operands[1], AS1 (fild%z0,%1)); | |
1341 | RET; | |
1342 | } | |
1343 | else if (GET_CODE (operands[1]) == MEM) | |
1344 | return AS1 (fild%z1,%1); | |
1345 | else | |
1346 | abort (); | |
1347 | }") | |
1348 | \f | |
1349 | ;;- add instructions | |
1350 | ||
1351 | (define_insn "adddi3" | |
1352 | [(set (match_operand:DI 0 "general_operand" "=&r,ro") | |
1353 | (plus:DI (match_operand:DI 1 "general_operand" "%0,0") | |
1354 | (match_operand:DI 2 "general_operand" "o,riF")))] | |
1355 | "" | |
1356 | "* | |
1357 | { | |
1358 | rtx low[3], high[3]; | |
1359 | ||
1360 | CC_STATUS_INIT; | |
1361 | ||
1362 | split_di (operands, 3, low, high); | |
1363 | ||
1364 | output_asm_insn (AS2 (add%L0,%2,%0), low); | |
1365 | output_asm_insn (AS2 (adc%L0,%2,%0), high); | |
1366 | RET; | |
1367 | }") | |
1368 | ||
1369 | ;; On a 486, it is faster to do movl/addl than to do a single leal if | |
1370 | ;; operands[1] and operands[2] are both registers. | |
1371 | ||
1372 | (define_insn "addsi3" | |
1373 | [(set (match_operand:SI 0 "general_operand" "=?r,rm,r") | |
1374 | (plus:SI (match_operand:SI 1 "general_operand" "%r,0,0") | |
1375 | (match_operand:SI 2 "general_operand" "ri,ri,rm")))] | |
1376 | "" | |
1377 | "* | |
1378 | { | |
1379 | if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1])) | |
1380 | { | |
1381 | if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2])) | |
1382 | return AS2 (add%L0,%1,%0); | |
1383 | ||
1384 | if (! TARGET_486 || ! REG_P (operands[2])) | |
1385 | { | |
1386 | CC_STATUS_INIT; | |
1387 | operands[1] = SET_SRC (PATTERN (insn)); | |
1388 | return AS2 (lea%L0,%a1,%0); | |
1389 | } | |
1390 | ||
1391 | output_asm_insn (AS2 (mov%L0,%1,%0), operands); | |
1392 | } | |
1393 | ||
1394 | if (operands[2] == const1_rtx) | |
1395 | return AS1 (inc%L0,%0); | |
1396 | ||
1397 | if (operands[2] == constm1_rtx) | |
1398 | return AS1 (dec%L0,%0); | |
1399 | ||
1400 | return AS2 (add%L0,%2,%0); | |
1401 | }") | |
1402 | ||
1403 | ;; ??? `lea' here, for three operand add? If leaw is used, only %bx, | |
1404 | ;; %si and %di can appear in SET_SRC, and output_asm_insn might not be | |
1405 | ;; able to handle the operand. But leal always works? | |
1406 | ||
1407 | (define_insn "addhi3" | |
1408 | [(set (match_operand:HI 0 "general_operand" "=rm,r") | |
1409 | (plus:HI (match_operand:HI 1 "general_operand" "%0,0") | |
1410 | (match_operand:HI 2 "general_operand" "ri,rm")))] | |
1411 | "" | |
1412 | "* | |
1413 | { | |
1414 | if (operands[2] == const1_rtx) | |
1415 | return AS1 (inc%W0,%0); | |
1416 | ||
1417 | if (operands[2] == constm1_rtx) | |
1418 | return AS1 (dec%W0,%0); | |
1419 | ||
1420 | return AS2 (add%W0,%2,%0); | |
1421 | }") | |
1422 | ||
1423 | (define_insn "addqi3" | |
1424 | [(set (match_operand:QI 0 "general_operand" "=qm,q") | |
1425 | (plus:QI (match_operand:QI 1 "general_operand" "%0,0") | |
1426 | (match_operand:QI 2 "general_operand" "qn,qmn")))] | |
1427 | "" | |
1428 | "* | |
1429 | { | |
1430 | if (operands[2] == const1_rtx) | |
1431 | return AS1 (inc%B0,%0); | |
1432 | ||
1433 | if (operands[2] == constm1_rtx) | |
1434 | return AS1 (dec%B0,%0); | |
1435 | ||
1436 | return AS2 (add%B0,%2,%0); | |
1437 | }") | |
1438 | ||
1439 | ;Lennart Augustsson <augustss@cs.chalmers.se> | |
1440 | ;says this pattern just makes slower code: | |
1441 | ; pushl %ebp | |
1442 | ; addl $-80,(%esp) | |
1443 | ;instead of | |
1444 | ; leal -80(%ebp),%eax | |
1445 | ; pushl %eax | |
1446 | ; | |
1447 | ;(define_insn "" | |
1448 | ; [(set (match_operand:SI 0 "push_operand" "=<") | |
1449 | ; (plus:SI (match_operand:SI 1 "general_operand" "%r") | |
1450 | ; (match_operand:SI 2 "general_operand" "ri")))] | |
1451 | ; "" | |
1452 | ; "* | |
1453 | ;{ | |
1454 | ; rtx xops[4]; | |
1455 | ; xops[0] = operands[0]; | |
1456 | ; xops[1] = operands[1]; | |
1457 | ; xops[2] = operands[2]; | |
1458 | ; xops[3] = gen_rtx (MEM, SImode, stack_pointer_rtx); | |
1459 | ; output_asm_insn (\"push%z1 %1\", xops); | |
1460 | ; output_asm_insn (AS2 (add%z3,%2,%3), xops); | |
1461 | ; RET; | |
1462 | ;}") | |
1463 | ||
1464 | ;; addsi3 is faster, so put this after. | |
1465 | ||
1466 | (define_insn "" | |
1467 | [(set (match_operand:SI 0 "register_operand" "=r") | |
1468 | (match_operand:QI 1 "address_operand" "p"))] | |
1469 | "" | |
1470 | "* | |
1471 | { | |
1472 | CC_STATUS_INIT; | |
1473 | /* Adding a constant to a register is faster with an add. */ | |
1474 | /* ??? can this ever happen? */ | |
1475 | if (GET_CODE (operands[1]) == PLUS | |
1476 | && GET_CODE (XEXP (operands[1], 1)) == CONST_INT | |
1477 | && rtx_equal_p (operands[0], XEXP (operands[1], 0))) | |
1478 | { | |
1479 | operands[1] = XEXP (operands[1], 1); | |
1480 | ||
1481 | if (operands[1] == const1_rtx) | |
1482 | return AS1 (inc%L0,%0); | |
1483 | ||
1484 | if (operands[1] == constm1_rtx) | |
1485 | return AS1 (dec%L0,%0); | |
1486 | ||
1487 | return AS2 (add%L0,%1,%0); | |
1488 | } | |
1489 | return AS2 (lea%L0,%a1,%0); | |
1490 | }") | |
1491 | ||
1492 | ;; The patterns that match these are at the end of this file. | |
1493 | ||
1494 | (define_expand "adddf3" | |
1495 | [(set (match_operand:DF 0 "register_operand" "") | |
1496 | (plus:DF (match_operand:DF 1 "nonimmediate_operand" "") | |
1497 | (match_operand:DF 2 "nonimmediate_operand" "")))] | |
1498 | "TARGET_80387" | |
1499 | "") | |
1500 | ||
1501 | (define_expand "addsf3" | |
1502 | [(set (match_operand:SF 0 "register_operand" "") | |
1503 | (plus:SF (match_operand:SF 1 "nonimmediate_operand" "") | |
1504 | (match_operand:SF 2 "nonimmediate_operand" "")))] | |
1505 | "TARGET_80387" | |
1506 | "") | |
1507 | \f | |
1508 | ;;- subtract instructions | |
1509 | ||
1510 | (define_insn "subdi3" | |
1511 | [(set (match_operand:DI 0 "general_operand" "=&r,ro") | |
1512 | (minus:DI (match_operand:DI 1 "general_operand" "0,0") | |
1513 | (match_operand:DI 2 "general_operand" "o,riF")))] | |
1514 | "" | |
1515 | "* | |
1516 | { | |
1517 | rtx low[3], high[3]; | |
1518 | ||
1519 | CC_STATUS_INIT; | |
1520 | ||
1521 | split_di (operands, 3, low, high); | |
1522 | ||
1523 | output_asm_insn (AS2 (sub%L0,%2,%0), low); | |
1524 | output_asm_insn (AS2 (sbb%L0,%2,%0), high); | |
1525 | RET; | |
1526 | }") | |
1527 | ||
1528 | (define_insn "subsi3" | |
1529 | [(set (match_operand:SI 0 "general_operand" "=rm,r") | |
1530 | (minus:SI (match_operand:SI 1 "general_operand" "0,0") | |
1531 | (match_operand:SI 2 "general_operand" "ri,rm")))] | |
1532 | "" | |
1533 | "* return AS2 (sub%L0,%2,%0);") | |
1534 | ||
1535 | (define_insn "subhi3" | |
1536 | [(set (match_operand:HI 0 "general_operand" "=rm,r") | |
1537 | (minus:HI (match_operand:HI 1 "general_operand" "0,0") | |
1538 | (match_operand:HI 2 "general_operand" "ri,rm")))] | |
1539 | "" | |
1540 | "* return AS2 (sub%W0,%2,%0);") | |
1541 | ||
1542 | (define_insn "subqi3" | |
1543 | [(set (match_operand:QI 0 "general_operand" "=qm,q") | |
1544 | (minus:QI (match_operand:QI 1 "general_operand" "0,0") | |
1545 | (match_operand:QI 2 "general_operand" "qn,qmn")))] | |
1546 | "" | |
1547 | "* return AS2 (sub%B0,%2,%0);") | |
1548 | ||
1549 | ;; The patterns that match these are at the end of this file. | |
1550 | ||
1551 | (define_expand "subdf3" | |
1552 | [(set (match_operand:DF 0 "register_operand" "") | |
1553 | (minus:DF (match_operand:DF 1 "nonimmediate_operand" "") | |
1554 | (match_operand:DF 2 "nonimmediate_operand" "")))] | |
1555 | "TARGET_80387" | |
1556 | "") | |
1557 | ||
1558 | (define_expand "subsf3" | |
1559 | [(set (match_operand:SF 0 "register_operand" "") | |
1560 | (minus:SF (match_operand:SF 1 "nonimmediate_operand" "") | |
1561 | (match_operand:SF 2 "nonimmediate_operand" "")))] | |
1562 | "TARGET_80387" | |
1563 | "") | |
1564 | \f | |
1565 | ;;- multiply instructions | |
1566 | ||
1567 | ;(define_insn "mulqi3" | |
1568 | ; [(set (match_operand:QI 0 "general_operand" "=a") | |
1569 | ; (mult:QI (match_operand:QI 1 "general_operand" "%0") | |
1570 | ; (match_operand:QI 2 "general_operand" "qm")))] | |
1571 | ; "" | |
1572 | ; "imul%B0 %2,%0") | |
1573 | ||
1574 | (define_insn "" | |
1575 | [(set (match_operand:HI 0 "general_operand" "=r") | |
1576 | (mult:SI (match_operand:HI 1 "general_operand" "%0") | |
1577 | (match_operand:HI 2 "general_operand" "r")))] | |
1578 | "GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80" | |
1579 | "* return AS2 (imul%W0,%2,%0);") | |
1580 | ||
1581 | (define_insn "mulhi3" | |
1582 | [(set (match_operand:HI 0 "general_operand" "=r,r") | |
1583 | (mult:SI (match_operand:HI 1 "general_operand" "%0,rm") | |
1584 | (match_operand:HI 2 "general_operand" "g,i")))] | |
1585 | "" | |
1586 | "* | |
1587 | { | |
1588 | if (GET_CODE (operands[1]) == REG | |
1589 | && REGNO (operands[1]) == REGNO (operands[0]) | |
1590 | && (GET_CODE (operands[2]) == MEM || GET_CODE (operands[2]) == REG)) | |
1591 | /* Assembler has weird restrictions. */ | |
1592 | return AS2 (imul%W0,%2,%0); | |
1593 | return AS3 (imul%W0,%2,%1,%0); | |
1594 | }") | |
1595 | ||
1596 | (define_insn "" | |
1597 | [(set (match_operand:SI 0 "general_operand" "=r") | |
1598 | (mult:SI (match_operand:SI 1 "general_operand" "%0") | |
1599 | (match_operand:SI 2 "general_operand" "r")))] | |
1600 | "GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80" | |
1601 | "* return AS2 (imul%L0,%2,%0);") | |
1602 | ||
1603 | (define_insn "mulsi3" | |
1604 | [(set (match_operand:SI 0 "general_operand" "=r,r") | |
1605 | (mult:SI (match_operand:SI 1 "general_operand" "%0,rm") | |
1606 | (match_operand:SI 2 "general_operand" "g,i")))] | |
1607 | "" | |
1608 | "* | |
1609 | { | |
1610 | if (GET_CODE (operands[1]) == REG | |
1611 | && REGNO (operands[1]) == REGNO (operands[0]) | |
1612 | && (GET_CODE (operands[2]) == MEM || GET_CODE (operands[2]) == REG)) | |
1613 | /* Assembler has weird restrictions. */ | |
1614 | return AS2 (imul%L0,%2,%0); | |
1615 | return AS3 (imul%L0,%2,%1,%0); | |
1616 | }") | |
1617 | ||
c572e5ba | 1618 | (define_insn "" |
886c62d1 JVA |
1619 | [(set (match_operand:HI 0 "general_operand" "=a") |
1620 | (mult:SI (zero_extend:HI | |
1621 | (match_operand:QI 1 "nonimmediate_operand" "%0")) | |
1622 | (zero_extend:HI | |
1623 | (match_operand:QI 2 "nonimmediate_operand" "qm"))))] | |
1624 | "" | |
1625 | "mul%B0 %2") | |
1626 | ||
1627 | ;; The patterns that match these are at the end of this file. | |
1628 | ||
1629 | (define_expand "muldf3" | |
1630 | [(set (match_operand:DF 0 "register_operand" "") | |
1631 | (mult:DF (match_operand:DF 1 "nonimmediate_operand" "") | |
1632 | (match_operand:DF 2 "nonimmediate_operand" "")))] | |
1633 | "TARGET_80387" | |
1634 | "") | |
1635 | ||
1636 | (define_expand "mulsf3" | |
1637 | [(set (match_operand:SF 0 "register_operand" "") | |
1638 | (mult:SF (match_operand:SF 1 "nonimmediate_operand" "") | |
1639 | (match_operand:SF 2 "nonimmediate_operand" "")))] | |
1640 | "TARGET_80387" | |
1641 | "") | |
1642 | \f | |
1643 | ;;- divide instructions | |
1644 | ||
1645 | (define_insn "divqi3" | |
1646 | [(set (match_operand:QI 0 "general_operand" "=a") | |
1647 | (div:QI (match_operand:HI 1 "general_operand" "0") | |
1648 | (match_operand:QI 2 "general_operand" "qm")))] | |
1649 | "" | |
1650 | "idiv%B0 %2") | |
1651 | ||
1652 | (define_insn "udivqi3" | |
1653 | [(set (match_operand:QI 0 "general_operand" "=a") | |
1654 | (udiv:QI (match_operand:HI 1 "general_operand" "0") | |
1655 | (match_operand:QI 2 "general_operand" "qm")))] | |
1656 | "" | |
1657 | "div%B0 %2") | |
1658 | ||
1659 | ;; The patterns that match these are at the end of this file. | |
1660 | ||
1661 | (define_expand "divdf3" | |
1662 | [(set (match_operand:DF 0 "register_operand" "") | |
1663 | (div:DF (match_operand:DF 1 "nonimmediate_operand" "") | |
1664 | (match_operand:DF 2 "nonimmediate_operand" "")))] | |
1665 | "TARGET_80387" | |
1666 | "") | |
1667 | ||
1668 | (define_expand "divsf3" | |
1669 | [(set (match_operand:SF 0 "register_operand" "") | |
1670 | (div:SF (match_operand:SF 1 "nonimmediate_operand" "") | |
1671 | (match_operand:SF 2 "nonimmediate_operand" "")))] | |
1672 | "TARGET_80387" | |
1673 | "") | |
1674 | \f | |
1675 | ;; Remainder instructions. | |
1676 | ||
1677 | (define_insn "divmodsi4" | |
2bb7a0f5 RS |
1678 | [(set (match_operand:SI 0 "register_operand" "=a") |
1679 | (div:SI (match_operand:SI 1 "register_operand" "0") | |
886c62d1 | 1680 | (match_operand:SI 2 "general_operand" "rm"))) |
2bb7a0f5 | 1681 | (set (match_operand:SI 3 "register_operand" "=&d") |
886c62d1 JVA |
1682 | (mod:SI (match_dup 1) (match_dup 2)))] |
1683 | "" | |
1684 | "* | |
1685 | { | |
1686 | #ifdef INTEL_SYNTAX | |
1687 | output_asm_insn (\"cdq\", operands); | |
1688 | #else | |
1689 | output_asm_insn (\"cltd\", operands); | |
1690 | #endif | |
1691 | return AS1 (idiv%L0,%2); | |
1692 | }") | |
1693 | ||
1694 | (define_insn "divmodhi4" | |
2bb7a0f5 RS |
1695 | [(set (match_operand:HI 0 "register_operand" "=a") |
1696 | (div:HI (match_operand:HI 1 "register_operand" "0") | |
886c62d1 | 1697 | (match_operand:HI 2 "general_operand" "rm"))) |
2bb7a0f5 | 1698 | (set (match_operand:HI 3 "register_operand" "=&d") |
886c62d1 JVA |
1699 | (mod:HI (match_dup 1) (match_dup 2)))] |
1700 | "" | |
1701 | "cwtd\;idiv%W0 %2") | |
1702 | ||
1703 | ;; ??? Can we make gcc zero extend operand[0]? | |
1704 | (define_insn "udivmodsi4" | |
2bb7a0f5 RS |
1705 | [(set (match_operand:SI 0 "register_operand" "=a") |
1706 | (udiv:SI (match_operand:SI 1 "register_operand" "0") | |
886c62d1 | 1707 | (match_operand:SI 2 "general_operand" "rm"))) |
2bb7a0f5 | 1708 | (set (match_operand:SI 3 "register_operand" "=&d") |
886c62d1 JVA |
1709 | (umod:SI (match_dup 1) (match_dup 2)))] |
1710 | "" | |
1711 | "* | |
1712 | { | |
1713 | output_asm_insn (AS2 (xor%L3,%3,%3), operands); | |
1714 | return AS1 (div%L0,%2); | |
1715 | }") | |
1716 | ||
1717 | ;; ??? Can we make gcc zero extend operand[0]? | |
1718 | (define_insn "udivmodhi4" | |
2bb7a0f5 RS |
1719 | [(set (match_operand:HI 0 "register_operand" "=a") |
1720 | (udiv:HI (match_operand:HI 1 "register_operand" "0") | |
886c62d1 | 1721 | (match_operand:HI 2 "general_operand" "rm"))) |
2bb7a0f5 | 1722 | (set (match_operand:HI 3 "register_operand" "=&d") |
886c62d1 JVA |
1723 | (umod:HI (match_dup 1) (match_dup 2)))] |
1724 | "" | |
1725 | "* | |
1726 | { | |
1727 | output_asm_insn (AS2 (xor%W0,%3,%3), operands); | |
1728 | return AS1 (div%W0,%2); | |
1729 | }") | |
1730 | ||
1731 | /* | |
1732 | ;;this should be a valid double division which we may want to add | |
1733 | ||
1734 | (define_insn "" | |
2bb7a0f5 RS |
1735 | [(set (match_operand:SI 0 "register_operand" "=a") |
1736 | (udiv:DI (match_operand:DI 1 "register_operand" "a") | |
1737 | (match_operand:SI 2 "general_operand" "rm"))) | |
1738 | (set (match_operand:SI 3 "register_operand" "=d") | |
886c62d1 JVA |
1739 | (umod:SI (match_dup 1) (match_dup 2)))] |
1740 | "" | |
1741 | "div%L0 %2,%0") | |
1742 | */ | |
1743 | \f | |
1744 | ;;- and instructions | |
1745 | ||
1746 | ;; On i386, | |
1747 | ;; movzbl %bl,%ebx | |
1748 | ;; is faster than | |
1749 | ;; andl $255,%ebx | |
1750 | ;; | |
1751 | ;; but if the reg is %eax, then the "andl" is faster. | |
1752 | ;; | |
1753 | ;; On i486, the "andl" is always faster than the "movzbl". | |
1754 | ;; | |
1755 | ;; On both i386 and i486, a three operand AND is as fast with movzbl or | |
1756 | ;; movzwl as with andl, if operands[0] != operands[1]. | |
1757 | ||
1758 | ;; The `r' in `rm' for operand 3 looks redundant, but it causes | |
1759 | ;; optional reloads to be generated if op 3 is a pseudo in a stack slot. | |
1760 | ||
1761 | ;; ??? What if we only change one byte of an offsettable memory reference? | |
1762 | (define_insn "andsi3" | |
1763 | [(set (match_operand:SI 0 "general_operand" "=r,r,rm,r") | |
1764 | (and:SI (match_operand:SI 1 "general_operand" "%rm,qm,0,0") | |
1765 | (match_operand:SI 2 "general_operand" "L,K,ri,rm")))] | |
1766 | "" | |
1767 | "* | |
1768 | { | |
1769 | if (GET_CODE (operands[2]) == CONST_INT | |
1770 | && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) | |
1771 | { | |
1772 | if (INTVAL (operands[2]) == 0xffff && REG_P (operands[0]) | |
1773 | && (! REG_P (operands[1]) | |
1774 | || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0) | |
1775 | && (! TARGET_486 || ! rtx_equal_p (operands[0], operands[1]))) | |
1776 | { | |
1777 | /* ??? tege: Should forget CC_STATUS only if we clobber a | |
1778 | remembered operand. Fix that later. */ | |
1779 | CC_STATUS_INIT; | |
1780 | #ifdef INTEL_SYNTAX | |
1781 | return AS2 (movzx,%w1,%0); | |
1782 | #else | |
1783 | return AS2 (movz%W0%L0,%w1,%0); | |
1784 | #endif | |
1785 | } | |
1786 | ||
1787 | if (INTVAL (operands[2]) == 0xff && REG_P (operands[0]) | |
1788 | && !(REG_P (operands[1]) && NON_QI_REG_P (operands[1])) | |
1789 | && (! REG_P (operands[1]) | |
1790 | || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0) | |
1791 | && (! TARGET_486 || ! rtx_equal_p (operands[0], operands[1]))) | |
1792 | { | |
1793 | /* ??? tege: Should forget CC_STATUS only if we clobber a | |
1794 | remembered operand. Fix that later. */ | |
1795 | CC_STATUS_INIT; | |
1796 | #ifdef INTEL_SYNTAX | |
1797 | return AS2 (movzx,%b1,%0); | |
1798 | #else | |
1799 | return AS2 (movz%B0%L0,%b1,%0); | |
1800 | #endif | |
1801 | } | |
1802 | ||
1803 | if (QI_REG_P (operands[0]) && ~(INTVAL (operands[2]) | 0xff) == 0) | |
1804 | { | |
1805 | CC_STATUS_INIT; | |
1806 | ||
1807 | if (INTVAL (operands[2]) == 0xffffff00) | |
1808 | { | |
1809 | operands[2] = const0_rtx; | |
1810 | return AS2 (mov%B0,%2,%b0); | |
1811 | } | |
1812 | ||
1813 | operands[2] = gen_rtx (CONST_INT, VOIDmode, | |
1814 | INTVAL (operands[2]) & 0xff); | |
1815 | return AS2 (and%B0,%2,%b0); | |
1816 | } | |
1817 | ||
1818 | if (QI_REG_P (operands[0]) && ~(INTVAL (operands[2]) | 0xff00) == 0) | |
1819 | { | |
1820 | CC_STATUS_INIT; | |
1821 | ||
1822 | if (INTVAL (operands[2]) == 0xffff00ff) | |
1823 | { | |
1824 | operands[2] = const0_rtx; | |
1825 | return AS2 (mov%B0,%2,%h0); | |
1826 | } | |
1827 | ||
1828 | operands[2] = gen_rtx (CONST_INT, VOIDmode, | |
1829 | INTVAL (operands[2]) >> 8); | |
1830 | return AS2 (and%B0,%2,%h0); | |
1831 | } | |
1832 | ||
1833 | if (GET_CODE (operands[0]) == MEM && INTVAL (operands[2]) == 0xffff0000) | |
1834 | { | |
1835 | operands[2] = const0_rtx; | |
1836 | return AS2 (mov%W0,%2,%w0); | |
1837 | } | |
1838 | } | |
1839 | ||
1840 | return AS2 (and%L0,%2,%0); | |
1841 | }") | |
1842 | ||
1843 | (define_insn "andhi3" | |
1844 | [(set (match_operand:HI 0 "general_operand" "=rm,r") | |
1845 | (and:HI (match_operand:HI 1 "general_operand" "%0,0") | |
1846 | (match_operand:HI 2 "general_operand" "ri,rm")))] | |
1847 | "" | |
1848 | "* | |
1849 | { | |
1850 | if (GET_CODE (operands[2]) == CONST_INT | |
1851 | && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) | |
1852 | { | |
1853 | /* Can we ignore the upper byte? */ | |
1854 | if (! NON_QI_REG_P (operands[0]) | |
1855 | && (INTVAL (operands[2]) & 0xff00) == 0xff00) | |
1856 | { | |
1857 | CC_STATUS_INIT; | |
1858 | ||
1859 | if ((INTVAL (operands[2]) & 0xff) == 0) | |
1860 | { | |
1861 | operands[2] = const0_rtx; | |
1862 | return AS2 (mov%B0,%2,%b0); | |
1863 | } | |
1864 | ||
1865 | operands[2] = gen_rtx (CONST_INT, VOIDmode, | |
1866 | INTVAL (operands[2]) & 0xff); | |
1867 | return AS2 (and%B0,%2,%b0); | |
1868 | } | |
1869 | ||
1870 | /* Can we ignore the lower byte? */ | |
1871 | /* ??? what about offsettable memory references? */ | |
1872 | if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & 0xff) == 0xff) | |
1873 | { | |
1874 | CC_STATUS_INIT; | |
1875 | ||
1876 | if ((INTVAL (operands[2]) & 0xff00) == 0) | |
1877 | { | |
1878 | operands[2] = const0_rtx; | |
1879 | return AS2 (mov%B0,%2,%h0); | |
1880 | } | |
1881 | ||
1882 | operands[2] = gen_rtx (CONST_INT, VOIDmode, | |
1883 | (INTVAL (operands[2]) >> 8) & 0xff); | |
1884 | return AS2 (and%B0,%2,%h0); | |
1885 | } | |
1886 | } | |
1887 | ||
1888 | return AS2 (and%W0,%2,%0); | |
1889 | }") | |
1890 | ||
1891 | (define_insn "andqi3" | |
1892 | [(set (match_operand:QI 0 "general_operand" "=qm,q") | |
1893 | (and:QI (match_operand:QI 1 "general_operand" "%0,0") | |
1894 | (match_operand:QI 2 "general_operand" "qn,qmn")))] | |
1895 | "" | |
1896 | "* return AS2 (and%B0,%2,%0);") | |
1897 | ||
1898 | /* I am nervous about these two.. add them later.. | |
1899 | ;I presume this means that we have something in say op0= eax which is small | |
1900 | ;and we want to and it with memory so we can do this by just an | |
1901 | ;andb m,%al and have success. | |
1902 | (define_insn "" | |
1903 | [(set (match_operand:SI 0 "general_operand" "=r") | |
1904 | (and:SI (zero_extend:SI | |
1905 | (match_operand:HI 1 "nonimmediate_operand" "rm")) | |
1906 | (match_operand:SI 2 "general_operand" "0")))] | |
1907 | "GET_CODE (operands[2]) == CONST_INT | |
1908 | && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))" | |
1909 | "and%W0 %1,%0") | |
1910 | ||
1911 | (define_insn "" | |
1912 | [(set (match_operand:SI 0 "general_operand" "=q") | |
1913 | (and:SI | |
1914 | (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")) | |
1915 | (match_operand:SI 2 "general_operand" "0")))] | |
1916 | "GET_CODE (operands[2]) == CONST_INT | |
1917 | && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))" | |
1918 | "and%L0 %1,%0") | |
1919 | ||
1920 | */ | |
1921 | \f | |
1922 | ;;- Bit set (inclusive or) instructions | |
1923 | ||
1924 | ;; ??? What if we only change one byte of an offsettable memory reference? | |
1925 | (define_insn "iorsi3" | |
1926 | [(set (match_operand:SI 0 "general_operand" "=rm,r") | |
1927 | (ior:SI (match_operand:SI 1 "general_operand" "%0,0") | |
1928 | (match_operand:SI 2 "general_operand" "ri,rm")))] | |
1929 | "" | |
1930 | "* | |
1931 | { | |
1932 | if (GET_CODE (operands[2]) == CONST_INT | |
1933 | && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) | |
1934 | { | |
1935 | if (! NON_QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff) == 0) | |
1936 | { | |
1937 | CC_STATUS_INIT; | |
1938 | ||
1939 | if (INTVAL (operands[2]) == 0xff) | |
1940 | return AS2 (mov%B0,%2,%b0); | |
1941 | ||
1942 | return AS2 (or%B0,%2,%b0); | |
1943 | } | |
1944 | ||
1945 | if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff00) == 0) | |
1946 | { | |
1947 | CC_STATUS_INIT; | |
1948 | operands[2] = gen_rtx (CONST_INT, VOIDmode, | |
1949 | INTVAL (operands[2]) >> 8); | |
1950 | ||
1951 | if (INTVAL (operands[2]) == 0xff) | |
1952 | return AS2 (mov%B0,%2,%h0); | |
1953 | ||
1954 | return AS2 (or%B0,%2,%h0); | |
1955 | } | |
1956 | } | |
1957 | ||
1958 | return AS2 (or%L0,%2,%0); | |
1959 | }") | |
1960 | ||
1961 | (define_insn "iorhi3" | |
1962 | [(set (match_operand:HI 0 "general_operand" "=rm,r") | |
1963 | (ior:HI (match_operand:HI 1 "general_operand" "%0,0") | |
1964 | (match_operand:HI 2 "general_operand" "ri,rm")))] | |
1965 | "" | |
1966 | "* | |
1967 | { | |
1968 | if (GET_CODE (operands[2]) == CONST_INT | |
1969 | && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) | |
1970 | { | |
1971 | /* Can we ignore the upper byte? */ | |
1972 | if (! NON_QI_REG_P (operands[0]) | |
1973 | && (INTVAL (operands[2]) & 0xff00) == 0) | |
1974 | { | |
1975 | CC_STATUS_INIT; | |
1976 | if (INTVAL (operands[2]) & 0xffff0000) | |
1977 | operands[2] = gen_rtx (CONST_INT, VOIDmode, | |
1978 | INTVAL (operands[2]) & 0xffff); | |
1979 | ||
1980 | if (INTVAL (operands[2]) == 0xff) | |
1981 | return AS2 (mov%B0,%2,%b0); | |
1982 | ||
1983 | return AS2 (or%B0,%2,%b0); | |
1984 | } | |
1985 | ||
1986 | /* Can we ignore the lower byte? */ | |
1987 | /* ??? what about offsettable memory references? */ | |
1988 | if (QI_REG_P (operands[0]) | |
1989 | && (INTVAL (operands[2]) & 0xff) == 0) | |
1990 | { | |
1991 | CC_STATUS_INIT; | |
1992 | operands[2] = gen_rtx (CONST_INT, VOIDmode, | |
1993 | (INTVAL (operands[2]) >> 8) & 0xff); | |
1994 | ||
1995 | if (INTVAL (operands[2]) == 0xff) | |
1996 | return AS2 (mov%B0,%2,%h0); | |
1997 | ||
1998 | return AS2 (or%B0,%2,%h0); | |
1999 | } | |
2000 | } | |
2001 | ||
2002 | return AS2 (or%W0,%2,%0); | |
2003 | }") | |
2004 | ||
2005 | (define_insn "iorqi3" | |
2006 | [(set (match_operand:QI 0 "general_operand" "=qm,q") | |
2007 | (ior:QI (match_operand:QI 1 "general_operand" "%0,0") | |
2008 | (match_operand:QI 2 "general_operand" "qn,qmn")))] | |
2009 | "" | |
2010 | "* return AS2 (or%B0,%2,%0);") | |
2011 | \f | |
2012 | ;;- xor instructions | |
2013 | ||
2014 | ;; ??? What if we only change one byte of an offsettable memory reference? | |
2015 | (define_insn "xorsi3" | |
2016 | [(set (match_operand:SI 0 "general_operand" "=rm,r") | |
2017 | (xor:SI (match_operand:SI 1 "general_operand" "%0,0") | |
2018 | (match_operand:SI 2 "general_operand" "ri,rm")))] | |
2019 | "" | |
2020 | "* | |
2021 | { | |
2022 | if (GET_CODE (operands[2]) == CONST_INT | |
2023 | && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) | |
2024 | { | |
2025 | if (! NON_QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff) == 0) | |
2026 | { | |
2027 | CC_STATUS_INIT; | |
2028 | ||
2029 | if (INTVAL (operands[2]) == 0xff) | |
b4ac57ab | 2030 | return AS1 (not%B0,%b0); |
886c62d1 JVA |
2031 | |
2032 | return AS2 (xor%B0,%2,%b0); | |
2033 | } | |
2034 | ||
2035 | if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff00) == 0) | |
2036 | { | |
2037 | CC_STATUS_INIT; | |
2038 | operands[2] = gen_rtx (CONST_INT, VOIDmode, | |
2039 | INTVAL (operands[2]) >> 8); | |
2040 | ||
2041 | if (INTVAL (operands[2]) == 0xff) | |
2042 | return AS1 (not%B0,%h0); | |
2043 | ||
2044 | return AS2 (xor%B0,%2,%h0); | |
2045 | } | |
2046 | } | |
2047 | ||
2048 | return AS2 (xor%L0,%2,%0); | |
2049 | }") | |
2050 | ||
2051 | (define_insn "xorhi3" | |
2052 | [(set (match_operand:HI 0 "general_operand" "=rm,r") | |
2053 | (xor:HI (match_operand:HI 1 "general_operand" "%0,0") | |
2054 | (match_operand:HI 2 "general_operand" "ri,rm")))] | |
2055 | "" | |
2056 | "* | |
2057 | { | |
2058 | if (GET_CODE (operands[2]) == CONST_INT | |
2059 | && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) | |
2060 | { | |
2061 | /* Can we ignore the upper byte? */ | |
2062 | if (! NON_QI_REG_P (operands[0]) | |
2063 | && (INTVAL (operands[2]) & 0xff00) == 0) | |
2064 | { | |
2065 | CC_STATUS_INIT; | |
2066 | if (INTVAL (operands[2]) & 0xffff0000) | |
2067 | operands[2] = gen_rtx (CONST_INT, VOIDmode, | |
2068 | INTVAL (operands[2]) & 0xffff); | |
2069 | ||
2070 | if (INTVAL (operands[2]) == 0xff) | |
b4ac57ab | 2071 | return AS1 (not%B0,%b0); |
886c62d1 JVA |
2072 | |
2073 | return AS2 (xor%B0,%2,%b0); | |
2074 | } | |
2075 | ||
2076 | /* Can we ignore the lower byte? */ | |
2077 | /* ??? what about offsettable memory references? */ | |
2078 | if (QI_REG_P (operands[0]) | |
2079 | && (INTVAL (operands[2]) & 0xff) == 0) | |
2080 | { | |
2081 | CC_STATUS_INIT; | |
2082 | operands[2] = gen_rtx (CONST_INT, VOIDmode, | |
2083 | (INTVAL (operands[2]) >> 8) & 0xff); | |
2084 | ||
2085 | if (INTVAL (operands[2]) == 0xff) | |
2086 | return AS1 (not%B0,%h0); | |
2087 | ||
2088 | return AS2 (xor%B0,%2,%h0); | |
2089 | } | |
2090 | } | |
2091 | ||
2092 | return AS2 (xor%W0,%2,%0); | |
2093 | }") | |
2094 | ||
2095 | (define_insn "xorqi3" | |
2096 | [(set (match_operand:QI 0 "general_operand" "=qm,q") | |
2097 | (xor:QI (match_operand:QI 1 "general_operand" "%0,0") | |
2098 | (match_operand:QI 2 "general_operand" "qn,qm")))] | |
2099 | "" | |
2100 | "* return AS2 (xor%B0,%2,%0);") | |
2101 | \f | |
2102 | ;;- negation instructions | |
2103 | ||
2104 | (define_insn "negdi2" | |
2105 | [(set (match_operand:DI 0 "general_operand" "=&ro") | |
2106 | (neg:DI (match_operand:DI 1 "general_operand" "0")))] | |
2107 | "" | |
2108 | "* | |
2109 | { | |
2110 | rtx xops[2], low[1], high[1]; | |
2111 | ||
2112 | CC_STATUS_INIT; | |
2113 | ||
2114 | split_di (operands, 1, low, high); | |
2115 | xops[0] = const0_rtx; | |
2116 | xops[1] = high[0]; | |
2117 | ||
2118 | output_asm_insn (AS1 (neg%L0,%0), low); | |
2119 | output_asm_insn (AS2 (adc%L1,%0,%1), xops); | |
2120 | output_asm_insn (AS1 (neg%L0,%0), high); | |
2121 | RET; | |
2122 | }") | |
2123 | ||
2124 | (define_insn "negsi2" | |
2125 | [(set (match_operand:SI 0 "general_operand" "=rm") | |
2126 | (neg:SI (match_operand:SI 1 "general_operand" "0")))] | |
2127 | "" | |
2128 | "neg%L0 %0") | |
2129 | ||
2130 | (define_insn "neghi2" | |
2131 | [(set (match_operand:HI 0 "general_operand" "=rm") | |
2132 | (neg:HI (match_operand:HI 1 "general_operand" "0")))] | |
2133 | "" | |
2134 | "neg%W0 %0") | |
2135 | ||
2136 | (define_insn "negqi2" | |
2137 | [(set (match_operand:QI 0 "general_operand" "=qm") | |
2138 | (neg:QI (match_operand:QI 1 "general_operand" "0")))] | |
2139 | "" | |
2140 | "neg%B0 %0") | |
2141 | ||
2142 | (define_insn "negsf2" | |
2143 | [(set (match_operand:SF 0 "register_operand" "=f") | |
2144 | (neg:SF (match_operand:SF 1 "general_operand" "0")))] | |
2145 | "TARGET_80387" | |
2146 | "fchs") | |
2147 | ||
2148 | (define_insn "negdf2" | |
2149 | [(set (match_operand:DF 0 "register_operand" "=f") | |
2150 | (neg:DF (match_operand:DF 1 "general_operand" "0")))] | |
2151 | "TARGET_80387" | |
2152 | "fchs") | |
2153 | ||
2154 | (define_insn "" | |
2155 | [(set (match_operand:DF 0 "register_operand" "=f") | |
2156 | (neg:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))] | |
2157 | "TARGET_80387" | |
2158 | "fchs") | |
2159 | \f | |
2160 | ;; Absolute value instructions | |
2161 | ||
2162 | (define_insn "abssf2" | |
2163 | [(set (match_operand:SF 0 "register_operand" "=f") | |
2164 | (abs:SF (match_operand:SF 1 "general_operand" "0")))] | |
2165 | "TARGET_80387" | |
2166 | "fabs") | |
2167 | ||
2168 | (define_insn "absdf2" | |
2169 | [(set (match_operand:DF 0 "register_operand" "=f") | |
2170 | (abs:DF (match_operand:DF 1 "general_operand" "0")))] | |
2171 | "TARGET_80387" | |
2172 | "fabs") | |
2173 | ||
2174 | (define_insn "" | |
2175 | [(set (match_operand:DF 0 "register_operand" "=f") | |
2176 | (abs:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))] | |
2177 | "TARGET_80387" | |
2178 | "fabs") | |
2179 | ||
2180 | (define_insn "sqrtsf2" | |
2181 | [(set (match_operand:SF 0 "register_operand" "=f") | |
2182 | (sqrt:SF (match_operand:SF 1 "general_operand" "0")))] | |
2183 | "TARGET_80387" | |
2184 | "fsqrt") | |
2185 | ||
2186 | (define_insn "sqrtdf2" | |
2187 | [(set (match_operand:DF 0 "register_operand" "=f") | |
2188 | (sqrt:DF (match_operand:DF 1 "general_operand" "0")))] | |
2189 | "TARGET_80387" | |
2190 | "fsqrt") | |
2191 | ||
2192 | (define_insn "" | |
2193 | [(set (match_operand:DF 0 "register_operand" "=f") | |
2194 | (sqrt:DF (float_extend:DF | |
2195 | (match_operand:SF 1 "general_operand" "0"))))] | |
2196 | "TARGET_80387" | |
2197 | "fsqrt") | |
2198 | \f | |
2199 | ;;- one complement instructions | |
2200 | ||
2201 | (define_insn "one_cmplsi2" | |
2202 | [(set (match_operand:SI 0 "general_operand" "=rm") | |
2203 | (not:SI (match_operand:SI 1 "general_operand" "0")))] | |
2204 | "" | |
2205 | "not%L0 %0") | |
2206 | ||
2207 | (define_insn "one_cmplhi2" | |
2208 | [(set (match_operand:HI 0 "general_operand" "=rm") | |
2209 | (not:HI (match_operand:HI 1 "general_operand" "0")))] | |
2210 | "" | |
2211 | "not%W0 %0") | |
2212 | ||
2213 | (define_insn "one_cmplqi2" | |
2214 | [(set (match_operand:QI 0 "general_operand" "=qm") | |
2215 | (not:QI (match_operand:QI 1 "general_operand" "0")))] | |
2216 | "" | |
2217 | "not%B0 %0") | |
2218 | \f | |
2219 | ;;- arithmetic shift instructions | |
2220 | ||
2221 | ;; DImode shifts are implemented using the i386 "shift double" opcode, | |
2222 | ;; which is written as "sh[lr]d[lw] imm,reg,reg/mem". If the shift count | |
2223 | ;; is variable, then the count is in %cl and the "imm" operand is dropped | |
2224 | ;; from the assembler input. | |
2225 | ||
2226 | ;; This instruction shifts the target reg/mem as usual, but instead of | |
2227 | ;; shifting in zeros, bits are shifted in from reg operand. If the insn | |
2228 | ;; is a left shift double, bits are taken from the high order bits of | |
2229 | ;; reg, else if the insn is a shift right double, bits are taken from the | |
2230 | ;; low order bits of reg. So if %eax is "1234" and %edx is "5678", | |
2231 | ;; "shldl $8,%edx,%eax" leaves %edx unchanged and sets %eax to "2345". | |
2232 | ||
2233 | ;; Since sh[lr]d does not change the `reg' operand, that is done | |
2234 | ;; separately, making all shifts emit pairs of shift double and normal | |
2235 | ;; shift. Since sh[lr]d does not shift more than 31 bits, and we wish to | |
2236 | ;; support a 63 bit shift, each shift where the count is in a reg expands | |
2237 | ;; to three pairs. If the overall shift is by N bits, then the first two | |
2238 | ;; pairs shift by N / 2 and the last pair by N & 1. | |
2239 | ||
2240 | ;; If the shift count is a constant, we need never emit more than one | |
2241 | ;; shift pair, instead using moves and sign extension for counts greater | |
2242 | ;; than 31. | |
2243 | ||
2244 | (define_insn "ashldi3" | |
2245 | [(set (match_operand:DI 0 "general_operand" "=&r") | |
2246 | (ashift:DI (match_operand:DI 1 "general_operand" "0") | |
2247 | (match_operand:QI 2 "general_operand" "cJ"))) | |
2248 | (clobber (match_dup 2))] | |
2249 | "" | |
2250 | "* | |
2251 | { | |
2252 | rtx xops[4], low[1], high[1]; | |
2253 | ||
2254 | CC_STATUS_INIT; | |
2255 | ||
2256 | split_di (operands, 1, low, high); | |
2257 | xops[0] = operands[2]; | |
2258 | xops[1] = const1_rtx; | |
2259 | xops[2] = low[0]; | |
2260 | xops[3] = high[0]; | |
2261 | ||
2262 | if (REG_P (xops[0])) /* If shift count in %cl */ | |
2263 | { | |
2264 | output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */ | |
2265 | ||
2266 | output_asm_insn (AS2 (shld%L3,%2,%3), xops); | |
2267 | output_asm_insn (AS2 (sal%L2,%0,%2), xops); | |
2268 | output_asm_insn (AS2 (shld%L3,%2,%3), xops); | |
2269 | output_asm_insn (AS2 (sal%L2,%0,%2), xops); | |
2270 | ||
2271 | xops[1] = gen_rtx (CONST_INT, VOIDmode, 7); /* shift count & 1 */ | |
2272 | ||
2273 | output_asm_insn (AS2 (shr%B0,%1,%0), xops); | |
2274 | ||
2275 | output_asm_insn (AS2 (shld%L3,%2,%3), xops); | |
2276 | output_asm_insn (AS2 (sal%L2,%0,%2), xops); | |
2277 | } | |
2278 | else if (GET_CODE (xops[0]) == CONST_INT) | |
2279 | { | |
2280 | if (INTVAL (xops[0]) > 31) | |
2281 | { | |
2282 | output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */ | |
2283 | output_asm_insn (AS2 (xor%L2,%2,%2), xops); | |
2284 | ||
2285 | if (INTVAL (xops[0]) > 32) | |
2286 | { | |
2287 | xops[0] = gen_rtx (CONST_INT, VOIDmode, INTVAL (xops[0]) - 32); | |
2288 | ||
2289 | output_asm_insn (AS2 (sal%3,%0,%3), xops); /* Remaining shift */ | |
2290 | } | |
2291 | } | |
2292 | else | |
2293 | { | |
2294 | output_asm_insn (AS3 (shld%L3,%0,%2,%3), xops); | |
2295 | output_asm_insn (AS2 (sal%L2,%0,%2), xops); | |
2296 | } | |
2297 | } | |
2298 | RET; | |
2299 | }") | |
2300 | ||
2301 | ;; On i386 and i486, "addl reg,reg" is faster than "sall $1,reg" | |
2302 | ;; On i486, movl/sall appears slightly faster than leal, but the leal | |
2303 | ;; is smaller - use leal for now unless the shift count is 1. | |
2304 | ||
2305 | (define_insn "ashlsi3" | |
2306 | [(set (match_operand:SI 0 "general_operand" "=r,rm") | |
2307 | (ashift:SI (match_operand:SI 1 "general_operand" "r,0") | |
2308 | (match_operand:SI 2 "general_operand" "M,cI")))] | |
2309 | "" | |
2310 | "* | |
2311 | { | |
2312 | if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1])) | |
2313 | { | |
2314 | if (TARGET_486 && INTVAL (operands[2]) == 1) | |
2315 | { | |
2316 | output_asm_insn (AS2 (mov%L0,%1,%0), operands); | |
2317 | return AS2 (add%L0,%1,%0); | |
2318 | } | |
2319 | else | |
2320 | { | |
2321 | CC_STATUS_INIT; | |
2322 | operands[1] = gen_rtx (MULT, SImode, operands[1], | |
2323 | gen_rtx (CONST_INT, VOIDmode, | |
2324 | 1 << INTVAL (operands[2]))); | |
2325 | return AS2 (lea%L0,%a1,%0); | |
2326 | } | |
2327 | } | |
2328 | ||
2329 | if (REG_P (operands[2])) | |
2330 | return AS2 (sal%L0,%b2,%0); | |
2331 | ||
2332 | if (REG_P (operands[0]) && operands[2] == const1_rtx) | |
2333 | return AS2 (add%L0,%0,%0); | |
2334 | ||
2335 | return AS2 (sal%L0,%2,%0); | |
2336 | }") | |
2337 | ||
2338 | (define_insn "ashlhi3" | |
2339 | [(set (match_operand:HI 0 "general_operand" "=rm") | |
2340 | (ashift:HI (match_operand:HI 1 "general_operand" "0") | |
2341 | (match_operand:HI 2 "general_operand" "cI")))] | |
2342 | "" | |
2343 | "* | |
2344 | { | |
2345 | if (REG_P (operands[2])) | |
2346 | return AS2 (sal%W0,%b2,%0); | |
2347 | ||
2348 | if (REG_P (operands[0]) && operands[2] == const1_rtx) | |
2349 | return AS2 (add%W0,%0,%0); | |
2350 | ||
2351 | return AS2 (sal%W0,%2,%0); | |
2352 | }") | |
2353 | ||
2354 | (define_insn "ashlqi3" | |
2355 | [(set (match_operand:QI 0 "general_operand" "=qm") | |
2356 | (ashift:QI (match_operand:QI 1 "general_operand" "0") | |
2357 | (match_operand:QI 2 "general_operand" "cI")))] | |
2358 | "" | |
2359 | "* | |
2360 | { | |
2361 | if (REG_P (operands[2])) | |
2362 | return AS2 (sal%B0,%b2,%0); | |
2363 | ||
2364 | if (REG_P (operands[0]) && operands[2] == const1_rtx) | |
2365 | return AS2 (add%B0,%0,%0); | |
2366 | ||
2367 | return AS2 (sal%B0,%2,%0); | |
2368 | }") | |
2369 | ||
2370 | ;; See comment above `ashldi3' about how this works. | |
2371 | ||
2372 | (define_insn "ashrdi3" | |
2373 | [(set (match_operand:DI 0 "general_operand" "=&r") | |
2374 | (ashiftrt:DI (match_operand:DI 1 "general_operand" "0") | |
2375 | (match_operand:QI 2 "general_operand" "cJ"))) | |
2376 | (clobber (match_dup 2))] | |
2377 | "" | |
2378 | "* | |
2379 | { | |
2380 | rtx xops[5], low[1], high[1]; | |
2381 | ||
2382 | CC_STATUS_INIT; | |
2383 | ||
2384 | split_di (operands, 1, low, high); | |
2385 | xops[0] = operands[2]; | |
2386 | xops[1] = const1_rtx; | |
2387 | xops[2] = low[0]; | |
2388 | xops[3] = high[0]; | |
2389 | ||
2390 | if (REG_P (xops[0])) /* If shift count in %cl */ | |
2391 | { | |
2392 | output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */ | |
2393 | ||
2394 | output_asm_insn (AS2 (shrd%L2,%3,%2), xops); | |
2395 | output_asm_insn (AS2 (sar%L3,%0,%3), xops); | |
2396 | output_asm_insn (AS2 (shrd%L2,%3,%2), xops); | |
2397 | output_asm_insn (AS2 (sar%L3,%0,%3), xops); | |
2398 | ||
2399 | xops[1] = gen_rtx (CONST_INT, VOIDmode, 7); /* shift count & 1 */ | |
2400 | ||
2401 | output_asm_insn (AS2 (shr%B0,%1,%0), xops); | |
2402 | ||
2403 | output_asm_insn (AS2 (shrd%L2,%3,%2), xops); | |
2404 | output_asm_insn (AS2 (sar%L3,%0,%3), xops); | |
2405 | } | |
2406 | else if (GET_CODE (xops[0]) == CONST_INT) | |
2407 | { | |
2408 | if (INTVAL (xops[0]) > 31) | |
2409 | { | |
2410 | xops[1] = gen_rtx (CONST_INT, VOIDmode, 31); | |
2411 | output_asm_insn (AS2 (mov%L2,%3,%2), xops); | |
2412 | output_asm_insn (AS2 (sar%L3,%1,%3), xops); /* shift by 32 */ | |
2413 | ||
2414 | if (INTVAL (xops[0]) > 32) | |
2415 | { | |
2416 | xops[0] = gen_rtx (CONST_INT, VOIDmode, INTVAL (xops[0]) - 32); | |
2417 | ||
2418 | output_asm_insn (AS2 (sar%2,%0,%2), xops); /* Remaining shift */ | |
2419 | } | |
2420 | } | |
2421 | else | |
2422 | { | |
2423 | output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops); | |
2424 | output_asm_insn (AS2 (sar%L3,%0,%3), xops); | |
2425 | } | |
2426 | } | |
2427 | RET; | |
2428 | }") | |
2429 | ||
2430 | (define_insn "ashrsi3" | |
2431 | [(set (match_operand:SI 0 "general_operand" "=rm") | |
2432 | (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") | |
2433 | (match_operand:SI 2 "general_operand" "cI")))] | |
2434 | "" | |
2435 | "* | |
2436 | { | |
2437 | if (REG_P (operands[2])) | |
2438 | return AS2 (sar%L0,%b2,%0); | |
2439 | else | |
2440 | return AS2 (sar%L0,%2,%0); | |
2441 | }") | |
2442 | ||
2443 | (define_insn "ashrhi3" | |
2444 | [(set (match_operand:HI 0 "general_operand" "=rm") | |
2445 | (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") | |
2446 | (match_operand:HI 2 "general_operand" "cI")))] | |
2447 | "" | |
2448 | "* | |
2449 | { | |
2450 | if (REG_P (operands[2])) | |
2451 | return AS2 (sar%W0,%b2,%0); | |
2452 | else | |
2453 | return AS2 (sar%W0,%2,%0); | |
2454 | }") | |
2455 | ||
2456 | (define_insn "ashrqi3" | |
2457 | [(set (match_operand:QI 0 "general_operand" "=qm") | |
2458 | (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") | |
2459 | (match_operand:QI 2 "general_operand" "cI")))] | |
2460 | "" | |
2461 | "* | |
2462 | { | |
2463 | if (REG_P (operands[2])) | |
2464 | return AS2 (sar%B0,%b2,%0); | |
2465 | else | |
2466 | return AS2 (sar%B0,%2,%0); | |
2467 | }") | |
2468 | \f | |
2469 | ;;- logical shift instructions | |
2470 | ||
2471 | ;; See comment above `ashldi3' about how this works. | |
2472 | ||
2473 | (define_insn "lshrdi3" | |
2474 | [(set (match_operand:DI 0 "general_operand" "=&r") | |
2475 | (lshiftrt:DI (match_operand:DI 1 "general_operand" "0") | |
2476 | (match_operand:QI 2 "general_operand" "cJ"))) | |
2477 | (clobber (match_dup 2))] | |
2478 | "" | |
2479 | "* | |
2480 | { | |
2481 | rtx xops[5], low[1], high[1]; | |
2482 | ||
2483 | CC_STATUS_INIT; | |
2484 | ||
2485 | split_di (operands, 1, low, high); | |
2486 | xops[0] = operands[2]; | |
2487 | xops[1] = const1_rtx; | |
2488 | xops[2] = low[0]; | |
2489 | xops[3] = high[0]; | |
2490 | ||
2491 | if (REG_P (xops[0])) /* If shift count in %cl */ | |
2492 | { | |
2493 | output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */ | |
2494 | ||
2495 | output_asm_insn (AS2 (shrd%L2,%3,%2), xops); | |
2496 | output_asm_insn (AS2 (shr%L3,%0,%3), xops); | |
2497 | output_asm_insn (AS2 (shrd%L2,%3,%2), xops); | |
2498 | output_asm_insn (AS2 (shr%L3,%0,%3), xops); | |
2499 | ||
2500 | xops[1] = gen_rtx (CONST_INT, VOIDmode, 7); /* shift count & 1 */ | |
2501 | ||
2502 | output_asm_insn (AS2 (shr%B0,%1,%0), xops); | |
2503 | ||
2504 | output_asm_insn (AS2 (shrd%L2,%3,%2), xops); | |
2505 | output_asm_insn (AS2 (shr%L3,%0,%3), xops); | |
2506 | } | |
2507 | else if (GET_CODE (xops[0]) == CONST_INT) | |
2508 | { | |
2509 | if (INTVAL (xops[0]) > 31) | |
2510 | { | |
2511 | output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */ | |
2512 | output_asm_insn (AS2 (xor%L3,%3,%3), xops); | |
2513 | ||
2514 | if (INTVAL (xops[0]) > 32) | |
2515 | { | |
2516 | xops[0] = gen_rtx (CONST_INT, VOIDmode, INTVAL (xops[0]) - 32); | |
2517 | ||
2518 | output_asm_insn (AS2 (shr%2,%0,%2), xops); /* Remaining shift */ | |
2519 | } | |
2520 | } | |
2521 | else | |
2522 | { | |
2523 | output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops); | |
2524 | output_asm_insn (AS2 (shr%L3,%0,%3), xops); | |
2525 | } | |
2526 | } | |
2527 | RET; | |
2528 | }") | |
2529 | ||
2530 | (define_insn "lshrsi3" | |
2531 | [(set (match_operand:SI 0 "general_operand" "=rm") | |
2532 | (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") | |
2533 | (match_operand:SI 2 "general_operand" "cI")))] | |
2534 | "" | |
2535 | "* | |
2536 | { | |
2537 | if (REG_P (operands[2])) | |
2538 | return AS2 (shr%L0,%b2,%0); | |
2539 | else | |
2540 | return AS2 (shr%L0,%2,%1); | |
2541 | }") | |
2542 | ||
2543 | (define_insn "lshrhi3" | |
2544 | [(set (match_operand:HI 0 "general_operand" "=rm") | |
2545 | (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") | |
2546 | (match_operand:HI 2 "general_operand" "cI")))] | |
2547 | "" | |
2548 | "* | |
2549 | { | |
2550 | if (REG_P (operands[2])) | |
2551 | return AS2 (shr%W0,%b2,%0); | |
2552 | else | |
2553 | return AS2 (shr%W0,%2,%0); | |
2554 | }") | |
2555 | ||
2556 | (define_insn "lshrqi3" | |
2557 | [(set (match_operand:QI 0 "general_operand" "=qm") | |
2558 | (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") | |
2559 | (match_operand:QI 2 "general_operand" "cI")))] | |
2560 | "" | |
2561 | "* | |
2562 | { | |
2563 | if (REG_P (operands[2])) | |
2564 | return AS2 (shr%B0,%b2,%0); | |
2565 | else | |
2566 | return AS2 (shr%B0,%2,%0); | |
2567 | }") | |
2568 | \f | |
2569 | ;;- rotate instructions | |
2570 | ||
2571 | (define_insn "rotlsi3" | |
2572 | [(set (match_operand:SI 0 "general_operand" "=rm") | |
2573 | (rotate:SI (match_operand:SI 1 "general_operand" "0") | |
2574 | (match_operand:SI 2 "general_operand" "cI")))] | |
2575 | "" | |
2576 | "* | |
2577 | { | |
2578 | if (REG_P (operands[2])) | |
2579 | return AS2 (rol%L0,%b2,%0); | |
2580 | else | |
2581 | return AS2 (rol%L0,%2,%0); | |
2582 | }") | |
2583 | ||
2584 | (define_insn "rotlhi3" | |
2585 | [(set (match_operand:HI 0 "general_operand" "=rm") | |
2586 | (rotate:HI (match_operand:HI 1 "general_operand" "0") | |
2587 | (match_operand:HI 2 "general_operand" "cI")))] | |
2588 | "" | |
2589 | "* | |
2590 | { | |
2591 | if (REG_P (operands[2])) | |
2592 | return AS2 (rol%W0,%b2,%0); | |
2593 | else | |
2594 | return AS2 (rol%W0,%2,%0); | |
2595 | }") | |
2596 | ||
2597 | (define_insn "rotlqi3" | |
2598 | [(set (match_operand:QI 0 "general_operand" "=qm") | |
2599 | (rotate:QI (match_operand:QI 1 "general_operand" "0") | |
2600 | (match_operand:QI 2 "general_operand" "cI")))] | |
2601 | "" | |
2602 | "* | |
2603 | { | |
2604 | if (REG_P (operands[2])) | |
2605 | return AS2 (rol%B0,%b2,%0); | |
2606 | else | |
2607 | return AS2 (rol%B0,%2,%0); | |
2608 | }") | |
2609 | ||
2610 | (define_insn "rotrsi3" | |
2611 | [(set (match_operand:SI 0 "general_operand" "=rm") | |
2612 | (rotatert:SI (match_operand:SI 1 "general_operand" "0") | |
2613 | (match_operand:SI 2 "general_operand" "cI")))] | |
2614 | "" | |
2615 | "* | |
2616 | { | |
2617 | if (REG_P (operands[2])) | |
2618 | return AS2 (ror%L0,%b2,%0); | |
2619 | else | |
2620 | return AS2 (ror%L0,%2,%0); | |
2621 | }") | |
2622 | ||
2623 | (define_insn "rotrhi3" | |
2624 | [(set (match_operand:HI 0 "general_operand" "=rm") | |
2625 | (rotatert:HI (match_operand:HI 1 "general_operand" "0") | |
2626 | (match_operand:HI 2 "general_operand" "cI")))] | |
2627 | "" | |
2628 | "* | |
2629 | { | |
2630 | if (REG_P (operands[2])) | |
2631 | return AS2 (ror%W0,%b2,%0); | |
2632 | else | |
2633 | return AS2 (ror%W0,%2,%0); | |
2634 | }") | |
2635 | ||
2636 | (define_insn "rotrqi3" | |
2637 | [(set (match_operand:QI 0 "general_operand" "=qm") | |
2638 | (rotatert:QI (match_operand:QI 1 "general_operand" "0") | |
2639 | (match_operand:QI 2 "general_operand" "cI")))] | |
2640 | "" | |
2641 | "* | |
2642 | { | |
2643 | if (REG_P (operands[2])) | |
2644 | return AS2 (ror%B0,%b2,%0); | |
2645 | else | |
2646 | return AS2 (ror%B0,%2,%0); | |
2647 | }") | |
2648 | \f | |
2649 | /* | |
2650 | ;; This usually looses. But try a define_expand to recognize a few case | |
2651 | ;; we can do efficiently, such as accessing the "high" QImode registers, | |
2652 | ;; %ah, %bh, %ch, %dh. | |
2653 | (define_insn "insv" | |
2654 | [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+&r") | |
2655 | (match_operand:SI 1 "general_operand" "i") | |
2656 | (match_operand:SI 2 "general_operand" "i")) | |
2657 | (match_operand:SI 3 "general_operand" "ri"))] | |
2658 | "" | |
2659 | "* | |
2660 | { | |
2661 | if (INTVAL (operands[1]) + INTVAL (operands[2]) > GET_MODE_BITSIZE (SImode)) | |
2662 | abort (); | |
2663 | if (GET_CODE (operands[3]) == CONST_INT) | |
2664 | { | |
2665 | unsigned int mask = (1 << INTVAL (operands[1])) - 1; | |
2666 | operands[1] = gen_rtx (CONST_INT, VOIDmode, | |
2667 | ~(mask << INTVAL (operands[2]))); | |
2668 | output_asm_insn (AS2 (and%L0,%1,%0), operands); | |
2669 | operands[3] = gen_rtx (CONST_INT, VOIDmode, | |
2670 | INTVAL (operands[3]) << INTVAL (operands[2])); | |
2671 | output_asm_insn (AS2 (or%L0,%3,%0), operands); | |
2672 | } | |
2673 | else | |
2674 | { | |
2675 | operands[0] = gen_rtx (REG, SImode, REGNO (operands[0])); | |
2676 | if (INTVAL (operands[2])) | |
2677 | output_asm_insn (AS2 (ror%L0,%2,%0), operands); | |
2678 | output_asm_insn (AS3 (shrd%L0,%1,%3,%0), operands); | |
2679 | operands[2] = gen_rtx (CONST_INT, VOIDmode, | |
2680 | BITS_PER_WORD | |
2681 | - INTVAL (operands[1]) - INTVAL (operands[2])); | |
2682 | if (INTVAL (operands[2])) | |
2683 | output_asm_insn (AS2 (ror%L0,%2,%0), operands); | |
2684 | } | |
2685 | RET; | |
2686 | }") | |
2687 | */ | |
2688 | /* | |
2689 | ;; ??? There are problems with the mode of operand[3]. The point of this | |
2690 | ;; is to represent an HImode move to a "high byte" register. | |
2691 | ||
2692 | (define_expand "insv" | |
2693 | [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "") | |
2694 | (match_operand:SI 1 "immediate_operand" "") | |
2695 | (match_operand:SI 2 "immediate_operand" "")) | |
2696 | (match_operand:QI 3 "general_operand" "ri"))] | |
2697 | "" | |
2698 | " | |
2699 | { | |
2700 | if (GET_CODE (operands[1]) != CONST_INT | |
2701 | || GET_CODE (operands[2]) != CONST_INT) | |
2702 | FAIL; | |
2703 | ||
2704 | if (! (INTVAL (operands[1]) == 8 | |
2705 | && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 0)) | |
2706 | && ! INTVAL (operands[1]) == 1) | |
2707 | FAIL; | |
2708 | }") | |
2709 | ||
2710 | ;; ??? Are these constraints right? | |
2711 | (define_insn "" | |
2712 | [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+&qo") | |
2713 | (const_int 8) | |
2714 | (const_int 8)) | |
2715 | (match_operand:QI 1 "general_operand" "qn"))] | |
2716 | "" | |
2717 | "* | |
2718 | { | |
2719 | if (REG_P (operands[0])) | |
2720 | return AS2 (mov%B0,%1,%h0); | |
2721 | ||
2722 | operands[0] = adj_offsettable_operand (operands[0], 1); | |
2723 | return AS2 (mov%B0,%1,%0); | |
2724 | }") | |
2725 | */ | |
2726 | ||
2727 | ;; On i386, the register count for a bit operation is *not* truncated, | |
2728 | ;; so SHIFT_COUNT_TRUNCATED must not be defined. | |
2729 | ||
2730 | ;; On i486, the shift & or/and code is faster than bts or btr. If | |
2731 | ;; operands[0] is a MEM, the bt[sr] is half as fast as the normal code. | |
2732 | ||
2733 | ;; On i386, bts is a little faster if operands[0] is a reg, and a | |
2734 | ;; little slower if operands[0] is a MEM, than the shift & or/and code. | |
2735 | ;; Use bts & btr, since they reload better. | |
2736 | ||
2737 | ;; General bit set and clear. | |
2738 | (define_insn "" | |
2739 | [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+rm") | |
2740 | (const_int 1) | |
4af3895e | 2741 | (match_operand:SI 2 "general_operand" "r")) |
886c62d1 | 2742 | (match_operand:SI 3 "immediate_operand" "i"))] |
4af3895e | 2743 | "! TARGET_486 && GET_CODE (operands[2]) != CONST_INT" |
886c62d1 JVA |
2744 | "* |
2745 | { | |
2746 | CC_STATUS_INIT; | |
2747 | ||
2748 | if (INTVAL (operands[3]) == 1) | |
2749 | return AS2 (bts%L0,%2,%0); | |
2750 | else | |
2751 | return AS2 (btr%L0,%2,%0); | |
2752 | }") | |
2753 | ||
2754 | ;; Bit complement. See comments on previous pattern. | |
2755 | ;; ??? Is this really worthwhile? | |
2756 | (define_insn "" | |
2757 | [(set (match_operand:SI 0 "general_operand" "+rm") | |
2758 | (xor:SI (ashift:SI (const_int 1) | |
2759 | (match_operand:SI 1 "general_operand" "r")) | |
2760 | (match_dup 0)))] | |
4af3895e | 2761 | "! TARGET_486 && GET_CODE (operands[1]) != CONST_INT" |
886c62d1 JVA |
2762 | "* |
2763 | { | |
2764 | CC_STATUS_INIT; | |
2765 | ||
2766 | return AS2 (btc%L0,%1,%0); | |
2767 | }") | |
2768 | ||
2769 | /* ??? This works, but that SUBREG looks dangerous. | |
2770 | (define_insn "" | |
2771 | [(set (match_operand:HI 0 "general_operand" "+rm") | |
2772 | (xor:HI (subreg:HI | |
2773 | (ashift:SI (const_int 1) | |
2774 | (sign_extend:SI | |
2775 | (match_operand:HI 1 "nonimmediate_operand" "r"))) 0) | |
2776 | (match_dup 0)))] | |
2777 | "! TARGET_486" | |
2778 | "* | |
2779 | { | |
2780 | CC_STATUS_INIT; | |
2781 | ||
2782 | return AS2 (btc%W0,%1,%0); | |
2783 | }") | |
2784 | */ | |
2785 | \f | |
2786 | ;; Recognizers for bit-test instructions. | |
2787 | ||
2788 | ;; The bt opcode allows a MEM in operands[0]. But on both i386 and | |
2789 | ;; i486, it is faster to copy a MEM to REG and then use bt, than to use | |
2790 | ;; bt on the MEM directly. | |
2791 | ||
b4ac57ab RS |
2792 | ;; ??? The first argument of a zero_extract must not be reloaded, so |
2793 | ;; don't allow a MEM in the operand predicate without allowing it in the | |
2794 | ;; constraint. | |
2795 | ||
886c62d1 | 2796 | (define_insn "" |
b4ac57ab | 2797 | [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r") |
886c62d1 | 2798 | (const_int 1) |
4af3895e JVA |
2799 | (match_operand:SI 1 "general_operand" "r")))] |
2800 | "GET_CODE (operands[1]) != CONST_INT" | |
886c62d1 JVA |
2801 | "* |
2802 | { | |
4af3895e JVA |
2803 | cc_status.flags |= CC_Z_IN_NOT_C; |
2804 | return AS2 (bt%L0,%1,%0); | |
886c62d1 JVA |
2805 | }") |
2806 | \f | |
2807 | ;; Store-flag instructions. | |
2808 | ||
c572e5ba JVA |
2809 | ;; For all sCOND expanders, also expand the compare or test insn that |
2810 | ;; generates cc0. Generate an equality comparison if `seq' or `sne'. | |
2811 | ||
2812 | (define_expand "seq" | |
2813 | [(match_dup 1) | |
2814 | (set (match_operand:QI 0 "general_operand" "") | |
2815 | (eq:QI (cc0) (const_int 0)))] | |
2816 | "" | |
2817 | " | |
2818 | { | |
2819 | if (TARGET_IEEE_FP | |
2820 | && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) | |
2821 | operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); | |
2822 | else | |
2823 | operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); | |
2824 | }") | |
2825 | ||
2826 | (define_insn "" | |
886c62d1 JVA |
2827 | [(set (match_operand:QI 0 "general_operand" "=qm") |
2828 | (eq:QI (cc0) (const_int 0)))] | |
2829 | "" | |
2830 | "* | |
2831 | { | |
2bb7a0f5 | 2832 | if (cc_prev_status.flags & CC_Z_IN_NOT_C) |
886c62d1 JVA |
2833 | return AS1 (setnb,%0); |
2834 | else | |
2835 | return AS1 (sete,%0); | |
c572e5ba | 2836 | }") |
886c62d1 | 2837 | |
c572e5ba JVA |
2838 | (define_expand "sne" |
2839 | [(match_dup 1) | |
2840 | (set (match_operand:QI 0 "general_operand" "") | |
2841 | (ne:QI (cc0) (const_int 0)))] | |
2842 | "" | |
2843 | " | |
2844 | { | |
2845 | if (TARGET_IEEE_FP | |
2846 | && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) | |
2847 | operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); | |
2848 | else | |
2849 | operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); | |
2850 | }") | |
2851 | ||
2852 | (define_insn "" | |
886c62d1 JVA |
2853 | [(set (match_operand:QI 0 "general_operand" "=qm") |
2854 | (ne:QI (cc0) (const_int 0)))] | |
2855 | "" | |
2856 | "* | |
2857 | { | |
2bb7a0f5 | 2858 | if (cc_prev_status.flags & CC_Z_IN_NOT_C) |
886c62d1 JVA |
2859 | return AS1 (setb,%0); |
2860 | else | |
2861 | return AS1 (setne,%0); | |
2862 | } | |
2863 | ") | |
2864 | ||
c572e5ba JVA |
2865 | (define_expand "sgt" |
2866 | [(match_dup 1) | |
2867 | (set (match_operand:QI 0 "general_operand" "") | |
2868 | (gt:QI (cc0) (const_int 0)))] | |
2869 | "" | |
2870 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
2871 | ||
2872 | (define_insn "" | |
886c62d1 JVA |
2873 | [(set (match_operand:QI 0 "general_operand" "=qm") |
2874 | (gt:QI (cc0) (const_int 0)))] | |
2875 | "" | |
c572e5ba JVA |
2876 | "* |
2877 | { | |
2878 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
2879 | return AS1 (sete,%0); | |
2880 | ||
2881 | OUTPUT_JUMP (\"setg %0\", \"seta %0\", 0); | |
2882 | }") | |
886c62d1 | 2883 | |
c572e5ba JVA |
2884 | (define_expand "sgtu" |
2885 | [(match_dup 1) | |
2886 | (set (match_operand:QI 0 "general_operand" "") | |
2887 | (gtu:QI (cc0) (const_int 0)))] | |
2888 | "" | |
2889 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
2890 | ||
2891 | (define_insn "" | |
886c62d1 JVA |
2892 | [(set (match_operand:QI 0 "general_operand" "=qm") |
2893 | (gtu:QI (cc0) (const_int 0)))] | |
2894 | "" | |
2895 | "* return \"seta %0\"; ") | |
2896 | ||
c572e5ba JVA |
2897 | (define_expand "slt" |
2898 | [(match_dup 1) | |
2899 | (set (match_operand:QI 0 "general_operand" "") | |
2900 | (lt:QI (cc0) (const_int 0)))] | |
2901 | "" | |
2902 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
2903 | ||
2904 | (define_insn "" | |
886c62d1 JVA |
2905 | [(set (match_operand:QI 0 "general_operand" "=qm") |
2906 | (lt:QI (cc0) (const_int 0)))] | |
2907 | "" | |
c572e5ba JVA |
2908 | "* |
2909 | { | |
2910 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
2911 | return AS1 (sete,%0); | |
886c62d1 | 2912 | |
c572e5ba JVA |
2913 | OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %0\"); |
2914 | }") | |
2915 | ||
2916 | (define_expand "sltu" | |
2917 | [(match_dup 1) | |
2918 | (set (match_operand:QI 0 "general_operand" "") | |
2919 | (ltu:QI (cc0) (const_int 0)))] | |
2920 | "" | |
2921 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
2922 | ||
2923 | (define_insn "" | |
886c62d1 JVA |
2924 | [(set (match_operand:QI 0 "general_operand" "=qm") |
2925 | (ltu:QI (cc0) (const_int 0)))] | |
2926 | "" | |
2927 | "* return \"setb %0\"; ") | |
2928 | ||
c572e5ba JVA |
2929 | (define_expand "sge" |
2930 | [(match_dup 1) | |
2931 | (set (match_operand:QI 0 "general_operand" "") | |
2932 | (ge:QI (cc0) (const_int 0)))] | |
2933 | "" | |
2934 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
2935 | ||
2936 | (define_insn "" | |
886c62d1 JVA |
2937 | [(set (match_operand:QI 0 "general_operand" "=qm") |
2938 | (ge:QI (cc0) (const_int 0)))] | |
2939 | "" | |
c572e5ba JVA |
2940 | "* |
2941 | { | |
2942 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
2943 | return AS1 (sete,%0); | |
886c62d1 | 2944 | |
c572e5ba JVA |
2945 | OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %0\"); |
2946 | }") | |
2947 | ||
2948 | (define_expand "sgeu" | |
2949 | [(match_dup 1) | |
2950 | (set (match_operand:QI 0 "general_operand" "") | |
2951 | (geu:QI (cc0) (const_int 0)))] | |
2952 | "" | |
2953 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
2954 | ||
2955 | (define_insn "" | |
886c62d1 JVA |
2956 | [(set (match_operand:QI 0 "general_operand" "=qm") |
2957 | (geu:QI (cc0) (const_int 0)))] | |
2958 | "" | |
2959 | "* return \"setae %0\"; ") | |
2960 | ||
c572e5ba JVA |
2961 | (define_expand "sle" |
2962 | [(match_dup 1) | |
2963 | (set (match_operand:QI 0 "general_operand" "") | |
2964 | (le:QI (cc0) (const_int 0)))] | |
2965 | "" | |
2966 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
2967 | ||
2968 | (define_insn "" | |
886c62d1 JVA |
2969 | [(set (match_operand:QI 0 "general_operand" "=qm") |
2970 | (le:QI (cc0) (const_int 0)))] | |
2971 | "" | |
c572e5ba JVA |
2972 | "* |
2973 | { | |
2974 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
2975 | return AS1 (setb,%0); | |
2976 | ||
2977 | OUTPUT_JUMP (\"setle %0\", \"setbe %0\", 0); | |
2978 | }") | |
886c62d1 JVA |
2979 | |
2980 | (define_insn "sleu" | |
2981 | [(set (match_operand:QI 0 "general_operand" "=qm") | |
2982 | (leu:QI (cc0) (const_int 0)))] | |
2983 | "" | |
2984 | "* return \"setbe %0\"; ") | |
2985 | \f | |
2986 | ;; Basic conditional jump instructions. | |
2987 | ;; We ignore the overflow flag for signed branch instructions. | |
2988 | ||
c572e5ba JVA |
2989 | ;; For all bCOND expanders, also expand the compare or test insn that |
2990 | ;; generates cc0. Generate an equality comparison if `beq' or `bne'. | |
2991 | ||
2992 | (define_expand "beq" | |
2993 | [(match_dup 1) | |
2994 | (set (pc) | |
2995 | (if_then_else (eq (cc0) | |
2996 | (const_int 0)) | |
2997 | (label_ref (match_operand 0 "" "")) | |
2998 | (pc)))] | |
2999 | "" | |
3000 | " | |
3001 | { | |
3002 | if (TARGET_IEEE_FP | |
3003 | && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) | |
3004 | operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); | |
3005 | else | |
3006 | operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); | |
3007 | }") | |
3008 | ||
3009 | (define_insn "" | |
886c62d1 JVA |
3010 | [(set (pc) |
3011 | (if_then_else (eq (cc0) | |
3012 | (const_int 0)) | |
3013 | (label_ref (match_operand 0 "" "")) | |
3014 | (pc)))] | |
3015 | "" | |
3016 | "* | |
3017 | { | |
2bb7a0f5 | 3018 | if (cc_prev_status.flags & CC_Z_IN_NOT_C) |
886c62d1 JVA |
3019 | return \"jnc %l0\"; |
3020 | else | |
3021 | return \"je %l0\"; | |
3022 | }") | |
3023 | ||
c572e5ba JVA |
3024 | (define_expand "bne" |
3025 | [(match_dup 1) | |
3026 | (set (pc) | |
3027 | (if_then_else (ne (cc0) | |
3028 | (const_int 0)) | |
3029 | (label_ref (match_operand 0 "" "")) | |
3030 | (pc)))] | |
3031 | "" | |
3032 | " | |
3033 | { | |
3034 | if (TARGET_IEEE_FP | |
3035 | && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) | |
3036 | operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); | |
3037 | else | |
3038 | operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); | |
3039 | }") | |
3040 | ||
3041 | (define_insn "" | |
886c62d1 JVA |
3042 | [(set (pc) |
3043 | (if_then_else (ne (cc0) | |
3044 | (const_int 0)) | |
3045 | (label_ref (match_operand 0 "" "")) | |
3046 | (pc)))] | |
3047 | "" | |
3048 | "* | |
3049 | { | |
2bb7a0f5 | 3050 | if (cc_prev_status.flags & CC_Z_IN_NOT_C) |
886c62d1 JVA |
3051 | return \"jc %l0\"; |
3052 | else | |
3053 | return \"jne %l0\"; | |
3054 | }") | |
3055 | ||
c572e5ba JVA |
3056 | (define_expand "bgt" |
3057 | [(match_dup 1) | |
3058 | (set (pc) | |
3059 | (if_then_else (gt (cc0) | |
3060 | (const_int 0)) | |
3061 | (label_ref (match_operand 0 "" "")) | |
3062 | (pc)))] | |
3063 | "" | |
3064 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
3065 | ||
3066 | (define_insn "" | |
886c62d1 JVA |
3067 | [(set (pc) |
3068 | (if_then_else (gt (cc0) | |
3069 | (const_int 0)) | |
3070 | (label_ref (match_operand 0 "" "")) | |
3071 | (pc)))] | |
3072 | "" | |
c572e5ba JVA |
3073 | "* |
3074 | { | |
3075 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
3076 | return AS1 (je,%l0); | |
3077 | ||
3078 | OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0); | |
3079 | }") | |
3080 | ||
3081 | (define_expand "bgtu" | |
3082 | [(match_dup 1) | |
3083 | (set (pc) | |
3084 | (if_then_else (gtu (cc0) | |
3085 | (const_int 0)) | |
3086 | (label_ref (match_operand 0 "" "")) | |
3087 | (pc)))] | |
3088 | "" | |
3089 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
886c62d1 | 3090 | |
c572e5ba | 3091 | (define_insn "" |
886c62d1 JVA |
3092 | [(set (pc) |
3093 | (if_then_else (gtu (cc0) | |
3094 | (const_int 0)) | |
3095 | (label_ref (match_operand 0 "" "")) | |
3096 | (pc)))] | |
3097 | "" | |
3098 | "ja %l0") | |
3099 | ||
886c62d1 | 3100 | (define_expand "blt" |
c572e5ba JVA |
3101 | [(match_dup 1) |
3102 | (set (pc) | |
886c62d1 JVA |
3103 | (if_then_else (lt (cc0) |
3104 | (const_int 0)) | |
3105 | (label_ref (match_operand 0 "" "")) | |
3106 | (pc)))] | |
3107 | "" | |
c572e5ba | 3108 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") |
886c62d1 JVA |
3109 | |
3110 | (define_insn "" | |
3111 | [(set (pc) | |
3112 | (if_then_else (lt (cc0) | |
3113 | (const_int 0)) | |
3114 | (label_ref (match_operand 0 "" "")) | |
3115 | (pc)))] | |
3116 | "" | |
c572e5ba JVA |
3117 | "* |
3118 | { | |
3119 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
3120 | return AS1 (je,%l0); | |
3121 | ||
3122 | OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\"); | |
3123 | }") | |
886c62d1 | 3124 | |
c572e5ba JVA |
3125 | (define_expand "bltu" |
3126 | [(match_dup 1) | |
3127 | (set (pc) | |
3128 | (if_then_else (ltu (cc0) | |
3129 | (const_int 0)) | |
3130 | (label_ref (match_operand 0 "" "")) | |
3131 | (pc)))] | |
3132 | "" | |
3133 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
3134 | ||
3135 | (define_insn "" | |
886c62d1 JVA |
3136 | [(set (pc) |
3137 | (if_then_else (ltu (cc0) | |
3138 | (const_int 0)) | |
3139 | (label_ref (match_operand 0 "" "")) | |
3140 | (pc)))] | |
3141 | "" | |
3142 | "jb %l0") | |
3143 | ||
c572e5ba JVA |
3144 | (define_expand "bge" |
3145 | [(match_dup 1) | |
3146 | (set (pc) | |
3147 | (if_then_else (ge (cc0) | |
3148 | (const_int 0)) | |
3149 | (label_ref (match_operand 0 "" "")) | |
3150 | (pc)))] | |
3151 | "" | |
3152 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
3153 | ||
3154 | (define_insn "" | |
886c62d1 JVA |
3155 | [(set (pc) |
3156 | (if_then_else (ge (cc0) | |
3157 | (const_int 0)) | |
3158 | (label_ref (match_operand 0 "" "")) | |
3159 | (pc)))] | |
3160 | "" | |
c572e5ba JVA |
3161 | "* |
3162 | { | |
3163 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
3164 | return AS1 (je,%l0); | |
3165 | ||
3166 | OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\"); | |
3167 | }") | |
3168 | ||
3169 | (define_expand "bgeu" | |
3170 | [(match_dup 1) | |
3171 | (set (pc) | |
3172 | (if_then_else (geu (cc0) | |
3173 | (const_int 0)) | |
3174 | (label_ref (match_operand 0 "" "")) | |
3175 | (pc)))] | |
3176 | "" | |
3177 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
886c62d1 | 3178 | |
c572e5ba | 3179 | (define_insn "" |
886c62d1 JVA |
3180 | [(set (pc) |
3181 | (if_then_else (geu (cc0) | |
3182 | (const_int 0)) | |
3183 | (label_ref (match_operand 0 "" "")) | |
3184 | (pc)))] | |
3185 | "" | |
3186 | "jae %l0") | |
3187 | ||
886c62d1 | 3188 | (define_expand "ble" |
c572e5ba JVA |
3189 | [(match_dup 1) |
3190 | (set (pc) | |
886c62d1 JVA |
3191 | (if_then_else (le (cc0) |
3192 | (const_int 0)) | |
3193 | (label_ref (match_operand 0 "" "")) | |
3194 | (pc)))] | |
3195 | "" | |
c572e5ba | 3196 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") |
886c62d1 JVA |
3197 | |
3198 | (define_insn "" | |
3199 | [(set (pc) | |
3200 | (if_then_else (le (cc0) | |
3201 | (const_int 0)) | |
3202 | (label_ref (match_operand 0 "" "")) | |
3203 | (pc)))] | |
3204 | "" | |
c572e5ba JVA |
3205 | "* |
3206 | { | |
3207 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
3208 | return AS1 (jb,%l0); | |
3209 | ||
3210 | OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0); | |
3211 | }") | |
3212 | ||
3213 | (define_expand "bleu" | |
3214 | [(match_dup 1) | |
3215 | (set (pc) | |
3216 | (if_then_else (leu (cc0) | |
3217 | (const_int 0)) | |
3218 | (label_ref (match_operand 0 "" "")) | |
3219 | (pc)))] | |
3220 | "" | |
3221 | "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") | |
886c62d1 | 3222 | |
c572e5ba | 3223 | (define_insn "" |
886c62d1 JVA |
3224 | [(set (pc) |
3225 | (if_then_else (leu (cc0) | |
3226 | (const_int 0)) | |
3227 | (label_ref (match_operand 0 "" "")) | |
3228 | (pc)))] | |
3229 | "" | |
3230 | "jbe %l0") | |
3231 | \f | |
3232 | ;; Negated conditional jump instructions. | |
3233 | ||
3234 | (define_insn "" | |
3235 | [(set (pc) | |
3236 | (if_then_else (eq (cc0) | |
3237 | (const_int 0)) | |
3238 | (pc) | |
3239 | (label_ref (match_operand 0 "" ""))))] | |
3240 | "" | |
3241 | "* | |
3242 | { | |
2bb7a0f5 | 3243 | if (cc_prev_status.flags & CC_Z_IN_NOT_C) |
886c62d1 JVA |
3244 | return \"jc %l0\"; |
3245 | else | |
3246 | return \"jne %l0\"; | |
3247 | }") | |
3248 | ||
3249 | (define_insn "" | |
3250 | [(set (pc) | |
3251 | (if_then_else (ne (cc0) | |
3252 | (const_int 0)) | |
3253 | (pc) | |
3254 | (label_ref (match_operand 0 "" ""))))] | |
3255 | "" | |
3256 | "* | |
3257 | { | |
2bb7a0f5 | 3258 | if (cc_prev_status.flags & CC_Z_IN_NOT_C) |
886c62d1 JVA |
3259 | return \"jnc %l0\"; |
3260 | else | |
3261 | return \"je %l0\"; | |
3262 | }") | |
3263 | ||
3264 | (define_insn "" | |
3265 | [(set (pc) | |
3266 | (if_then_else (gt (cc0) | |
3267 | (const_int 0)) | |
3268 | (pc) | |
3269 | (label_ref (match_operand 0 "" ""))))] | |
3270 | "" | |
c572e5ba JVA |
3271 | "* |
3272 | { | |
3273 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
3274 | return AS1 (jne,%l0); | |
3275 | ||
3276 | OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0); | |
3277 | }") | |
886c62d1 JVA |
3278 | |
3279 | (define_insn "" | |
3280 | [(set (pc) | |
3281 | (if_then_else (gtu (cc0) | |
3282 | (const_int 0)) | |
3283 | (pc) | |
3284 | (label_ref (match_operand 0 "" ""))))] | |
3285 | "" | |
3286 | "jbe %l0") | |
3287 | ||
3288 | (define_insn "" | |
3289 | [(set (pc) | |
3290 | (if_then_else (lt (cc0) | |
3291 | (const_int 0)) | |
3292 | (pc) | |
3293 | (label_ref (match_operand 0 "" ""))))] | |
3294 | "" | |
c572e5ba JVA |
3295 | "* |
3296 | { | |
3297 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
3298 | return AS1 (jne,%l0); | |
3299 | ||
3300 | OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\"); | |
3301 | }") | |
886c62d1 JVA |
3302 | |
3303 | (define_insn "" | |
3304 | [(set (pc) | |
3305 | (if_then_else (ltu (cc0) | |
3306 | (const_int 0)) | |
3307 | (pc) | |
3308 | (label_ref (match_operand 0 "" ""))))] | |
3309 | "" | |
3310 | "jae %l0") | |
3311 | ||
3312 | (define_insn "" | |
3313 | [(set (pc) | |
3314 | (if_then_else (ge (cc0) | |
3315 | (const_int 0)) | |
3316 | (pc) | |
3317 | (label_ref (match_operand 0 "" ""))))] | |
3318 | "" | |
c572e5ba JVA |
3319 | "* |
3320 | { | |
3321 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
3322 | return AS1 (jne,%l0); | |
3323 | ||
3324 | OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\"); | |
3325 | }") | |
886c62d1 JVA |
3326 | |
3327 | (define_insn "" | |
3328 | [(set (pc) | |
3329 | (if_then_else (geu (cc0) | |
3330 | (const_int 0)) | |
3331 | (pc) | |
3332 | (label_ref (match_operand 0 "" ""))))] | |
3333 | "" | |
3334 | "jb %l0") | |
3335 | ||
3336 | (define_insn "" | |
3337 | [(set (pc) | |
3338 | (if_then_else (le (cc0) | |
3339 | (const_int 0)) | |
3340 | (pc) | |
3341 | (label_ref (match_operand 0 "" ""))))] | |
3342 | "" | |
c572e5ba JVA |
3343 | "* |
3344 | { | |
3345 | if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) | |
3346 | return AS1 (jae,%l0); | |
3347 | ||
3348 | OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0); | |
3349 | }") | |
886c62d1 JVA |
3350 | |
3351 | (define_insn "" | |
3352 | [(set (pc) | |
3353 | (if_then_else (leu (cc0) | |
3354 | (const_int 0)) | |
3355 | (pc) | |
3356 | (label_ref (match_operand 0 "" ""))))] | |
3357 | "" | |
3358 | "ja %l0") | |
3359 | \f | |
3360 | ;; Unconditional and other jump instructions | |
3361 | ||
3362 | (define_insn "jump" | |
3363 | [(set (pc) | |
3364 | (label_ref (match_operand 0 "" "")))] | |
3365 | "" | |
3366 | "jmp %l0") | |
3367 | ||
3368 | (define_insn "indirect_jump" | |
2bb7a0f5 | 3369 | [(set (pc) (match_operand:SI 0 "general_operand" "rm"))] |
886c62d1 JVA |
3370 | "" |
3371 | "* | |
3372 | { | |
3373 | CC_STATUS_INIT; | |
3374 | ||
3375 | return AS1 (jmp,%*%0); | |
3376 | }") | |
3377 | ||
2bb7a0f5 RS |
3378 | ;; Implement switch statements when generating PIC code. Switches are |
3379 | ;; implemented by `tablejump' when not using -fpic. | |
3380 | ||
3381 | ;; Emit code here to do the range checking and make the index zero based. | |
3382 | ||
3383 | (define_expand "casesi" | |
b4ac57ab RS |
3384 | [(set (match_dup 5) |
3385 | (minus:SI (match_operand:SI 0 "general_operand" "") | |
3386 | (match_operand:SI 1 "general_operand" ""))) | |
3387 | (set (cc0) | |
c572e5ba JVA |
3388 | (compare:CC (match_dup 5) |
3389 | (match_operand:SI 2 "general_operand" ""))) | |
b4ac57ab RS |
3390 | (set (pc) |
3391 | (if_then_else (gtu (cc0) | |
3392 | (const_int 0)) | |
3393 | (label_ref (match_operand 4 "" "")) | |
3394 | (pc))) | |
3395 | (parallel | |
2bb7a0f5 | 3396 | [(set (pc) |
b4ac57ab RS |
3397 | (minus:SI (reg:SI 3) |
3398 | (mem:SI (plus:SI (mult:SI (match_dup 5) | |
3399 | (const_int 4)) | |
3400 | (label_ref (match_operand 3 "" "")))))) | |
3401 | (clobber (match_scratch:SI 6 ""))])] | |
2bb7a0f5 RS |
3402 | "flag_pic" |
3403 | " | |
3404 | { | |
b4ac57ab | 3405 | operands[5] = gen_reg_rtx (SImode); |
2bb7a0f5 | 3406 | current_function_uses_pic_offset_table = 1; |
2bb7a0f5 RS |
3407 | }") |
3408 | ||
3409 | ;; Implement a casesi insn. | |
3410 | ||
3411 | ;; Each entry in the "addr_diff_vec" looks like this as the result of the | |
3412 | ;; two rules below: | |
3413 | ;; | |
3414 | ;; .long _GLOBAL_OFFSET_TABLE_+[.-.L2] | |
3415 | ;; | |
3416 | ;; 1. An expression involving an external reference may only use the | |
3417 | ;; addition operator, and only with an assembly-time constant. | |
3418 | ;; The example above satisfies this because ".-.L2" is a constant. | |
3419 | ;; | |
3420 | ;; 2. The symbol _GLOBAL_OFFSET_TABLE_ is magic, and at link time is | |
3421 | ;; given the value of "GOT - .", where GOT is the actual address of | |
3422 | ;; the Global Offset Table. Therefore, the .long above actually | |
3423 | ;; stores the value "( GOT - . ) + [ . - .L2 ]", or "GOT - .L2". The | |
3424 | ;; expression "GOT - .L2" by itself would generate an error from as(1). | |
3425 | ;; | |
3426 | ;; The pattern below emits code that looks like this: | |
3427 | ;; | |
3428 | ;; movl %ebx,reg | |
3429 | ;; subl TABLE@GOTOFF(%ebx,index,4),reg | |
3430 | ;; jmp reg | |
3431 | ;; | |
3432 | ;; The addr_diff_vec contents may be directly referenced with @GOTOFF, since | |
3433 | ;; the addr_diff_vec is known to be part of this module. | |
3434 | ;; | |
3435 | ;; The subl above calculates "GOT - (( GOT - . ) + [ . - .L2 ])", which | |
3436 | ;; evaluates to just ".L2". | |
3437 | ||
3438 | (define_insn "" | |
3439 | [(set (pc) | |
b4ac57ab RS |
3440 | (minus:SI (reg:SI 3) |
3441 | (mem:SI (plus:SI | |
3442 | (mult:SI (match_operand:SI 0 "register_operand" "r") | |
3443 | (const_int 4)) | |
3444 | (label_ref (match_operand 1 "" "")))))) | |
3445 | (clobber (match_scratch:SI 2 "=&r"))] | |
2bb7a0f5 RS |
3446 | "" |
3447 | "* | |
3448 | { | |
3449 | rtx xops[4]; | |
3450 | ||
b4ac57ab RS |
3451 | xops[0] = operands[0]; |
3452 | xops[1] = operands[1]; | |
3453 | xops[2] = operands[2]; | |
3454 | xops[3] = pic_offset_table_rtx; | |
2bb7a0f5 | 3455 | |
b4ac57ab RS |
3456 | output_asm_insn (AS2 (mov%L2,%3,%2), xops); |
3457 | output_asm_insn (\"sub%L2 %l1@GOTOFF(%3,%0,4),%2\", xops); | |
3458 | output_asm_insn (AS1 (jmp,%*%2), xops); | |
2bb7a0f5 RS |
3459 | ASM_OUTPUT_ALIGN_CODE (asm_out_file); |
3460 | RET; | |
3461 | }") | |
3462 | ||
886c62d1 JVA |
3463 | (define_insn "tablejump" |
3464 | [(set (pc) (match_operand:SI 0 "general_operand" "rm")) | |
3465 | (use (label_ref (match_operand 1 "" "")))] | |
3466 | "" | |
3467 | "* | |
3468 | { | |
3469 | CC_STATUS_INIT; | |
3470 | ||
3471 | return AS1 (jmp,%*%0); | |
3472 | }") | |
3473 | ||
2bb7a0f5 RS |
3474 | ;; Call insns. |
3475 | ||
3476 | ;; If generating PIC code, the predicate indirect_operand will fail | |
3477 | ;; for operands[0] containing symbolic references on all of the named | |
3478 | ;; call* patterns. Each named pattern is followed by an unnamed pattern | |
3479 | ;; that matches any call to a symbolic CONST (ie, a symbol_ref). The | |
3480 | ;; unnamed patterns are only used while generating PIC code, because | |
3481 | ;; otherwise the named patterns match. | |
3482 | ||
886c62d1 JVA |
3483 | ;; Call subroutine returning no value. |
3484 | ||
2bb7a0f5 RS |
3485 | (define_expand "call_pop" |
3486 | [(parallel [(call (match_operand:QI 0 "indirect_operand" "") | |
3487 | (match_operand:SI 1 "general_operand" "")) | |
3488 | (set (reg:SI 7) | |
3489 | (plus:SI (reg:SI 7) | |
3490 | (match_operand:SI 3 "immediate_operand" "")))])] | |
3491 | "" | |
3492 | " | |
3493 | { | |
3494 | if (flag_pic) | |
3495 | current_function_uses_pic_offset_table = 1; | |
3496 | }") | |
3497 | ||
3498 | (define_insn "" | |
886c62d1 JVA |
3499 | [(call (match_operand:QI 0 "indirect_operand" "m") |
3500 | (match_operand:SI 1 "general_operand" "g")) | |
3501 | (set (reg:SI 7) (plus:SI (reg:SI 7) | |
3502 | (match_operand:SI 3 "immediate_operand" "i")))] | |
3503 | "" | |
3504 | "* | |
3505 | { | |
3506 | if (GET_CODE (operands[0]) == MEM | |
3507 | && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
3508 | { | |
3509 | operands[0] = XEXP (operands[0], 0); | |
3510 | return AS1 (call,%*%0); | |
3511 | } | |
3512 | else | |
3513 | return AS1 (call,%P0); | |
3514 | }") | |
3515 | ||
2bb7a0f5 RS |
3516 | (define_insn "" |
3517 | [(call (mem:QI (match_operand:SI 0 "symbolic_operand" "")) | |
3518 | (match_operand:SI 1 "general_operand" "g")) | |
3519 | (set (reg:SI 7) (plus:SI (reg:SI 7) | |
3520 | (match_operand:SI 3 "immediate_operand" "i")))] | |
3521 | "" | |
3522 | "call %P0") | |
3523 | ||
3524 | (define_expand "call" | |
3525 | [(call (match_operand:QI 0 "indirect_operand" "") | |
3526 | (match_operand:SI 1 "general_operand" ""))] | |
3527 | ;; Operand 1 not used on the i386. | |
3528 | "" | |
3529 | " | |
3530 | { | |
3531 | if (flag_pic) | |
3532 | current_function_uses_pic_offset_table = 1; | |
3533 | }") | |
3534 | ||
3535 | (define_insn "" | |
886c62d1 JVA |
3536 | [(call (match_operand:QI 0 "indirect_operand" "m") |
3537 | (match_operand:SI 1 "general_operand" "g"))] | |
3538 | ;; Operand 1 not used on the i386. | |
3539 | "" | |
3540 | "* | |
3541 | { | |
3542 | if (GET_CODE (operands[0]) == MEM | |
3543 | && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) | |
3544 | { | |
3545 | operands[0] = XEXP (operands[0], 0); | |
3546 | return AS1 (call,%*%0); | |
3547 | } | |
3548 | else | |
3549 | return AS1 (call,%P0); | |
3550 | }") | |
3551 | ||
2bb7a0f5 RS |
3552 | (define_insn "" |
3553 | [(call (mem:QI (match_operand:SI 0 "symbolic_operand" "")) | |
3554 | (match_operand:SI 1 "general_operand" "g"))] | |
3555 | ;; Operand 1 not used on the i386. | |
3556 | "" | |
3557 | "call %P0") | |
3558 | ||
886c62d1 JVA |
3559 | ;; Call subroutine, returning value in operand 0 |
3560 | ;; (which must be a hard register). | |
3561 | ||
2bb7a0f5 RS |
3562 | (define_expand "call_value_pop" |
3563 | [(parallel [(set (match_operand 0 "" "") | |
3564 | (call (match_operand:QI 1 "indirect_operand" "") | |
3565 | (match_operand:SI 2 "general_operand" ""))) | |
3566 | (set (reg:SI 7) | |
3567 | (plus:SI (reg:SI 7) | |
3568 | (match_operand:SI 4 "immediate_operand" "")))])] | |
3569 | "" | |
3570 | " | |
3571 | { | |
3572 | if (flag_pic) | |
3573 | current_function_uses_pic_offset_table = 1; | |
3574 | }") | |
3575 | ||
3576 | (define_insn "" | |
886c62d1 JVA |
3577 | [(set (match_operand 0 "" "=rf") |
3578 | (call (match_operand:QI 1 "indirect_operand" "m") | |
3579 | (match_operand:SI 2 "general_operand" "g"))) | |
3580 | (set (reg:SI 7) (plus:SI (reg:SI 7) | |
3581 | (match_operand:SI 4 "immediate_operand" "i")))] | |
3582 | "" | |
3583 | "* | |
3584 | { | |
3585 | if (GET_CODE (operands[1]) == MEM | |
3586 | && ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
3587 | { | |
3588 | operands[1] = XEXP (operands[1], 0); | |
3589 | output_asm_insn (AS1 (call,%*%1), operands); | |
3590 | } | |
3591 | else | |
3592 | output_asm_insn (AS1 (call,%P1), operands); | |
3593 | ||
3594 | RET; | |
3595 | }") | |
3596 | ||
2bb7a0f5 RS |
3597 | (define_insn "" |
3598 | [(set (match_operand 0 "" "=rf") | |
3599 | (call (mem:QI (match_operand:SI 1 "symbolic_operand" "")) | |
3600 | (match_operand:SI 2 "general_operand" "g"))) | |
3601 | (set (reg:SI 7) (plus:SI (reg:SI 7) | |
3602 | (match_operand:SI 4 "immediate_operand" "i")))] | |
3603 | "" | |
3604 | "call %P1") | |
3605 | ||
3606 | (define_expand "call_value" | |
3607 | [(set (match_operand 0 "" "") | |
3608 | (call (match_operand:QI 1 "indirect_operand" "") | |
3609 | (match_operand:SI 2 "general_operand" "")))] | |
3610 | ;; Operand 2 not used on the i386. | |
3611 | "" | |
3612 | " | |
3613 | { | |
3614 | if (flag_pic) | |
3615 | current_function_uses_pic_offset_table = 1; | |
3616 | }") | |
3617 | ||
3618 | (define_insn "" | |
886c62d1 JVA |
3619 | [(set (match_operand 0 "" "=rf") |
3620 | (call (match_operand:QI 1 "indirect_operand" "m") | |
3621 | (match_operand:SI 2 "general_operand" "g")))] | |
3622 | ;; Operand 2 not used on the i386. | |
3623 | "" | |
3624 | "* | |
3625 | { | |
3626 | if (GET_CODE (operands[1]) == MEM | |
3627 | && ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) | |
3628 | { | |
3629 | operands[1] = XEXP (operands[1], 0); | |
3630 | output_asm_insn (AS1 (call,%*%1), operands); | |
3631 | } | |
3632 | else | |
3633 | output_asm_insn (AS1 (call,%P1), operands); | |
3634 | ||
3635 | RET; | |
3636 | }") | |
3637 | ||
2bb7a0f5 RS |
3638 | (define_insn "" |
3639 | [(set (match_operand 0 "" "=rf") | |
3640 | (call (mem:QI (match_operand:SI 1 "symbolic_operand" "")) | |
3641 | (match_operand:SI 2 "general_operand" "g")))] | |
3642 | ;; Operand 2 not used on the i386. | |
3643 | "" | |
3644 | "call %P1") | |
3645 | ||
886c62d1 JVA |
3646 | ;; Insn emitted into the body of a function to return from a function. |
3647 | ;; This is only done if the function's epilogue is known to be simple. | |
3648 | ;; See comments for simple_386_epilogue in i386.c. | |
3649 | ||
3650 | (define_insn "return" | |
3651 | [(return)] | |
3652 | "simple_386_epilogue ()" | |
3653 | "* | |
3654 | { | |
3655 | function_epilogue (asm_out_file, get_frame_size ()); | |
3656 | RET; | |
3657 | }") | |
3658 | ||
3659 | (define_insn "nop" | |
3660 | [(const_int 0)] | |
3661 | "" | |
3662 | "nop") | |
3663 | ||
3664 | (define_expand "movstrsi" | |
3665 | [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" "")) | |
3666 | (mem:BLK (match_operand:BLK 1 "general_operand" ""))) | |
3667 | (use (match_operand:SI 2 "immediate_operand" "")) | |
3668 | (use (match_operand:SI 3 "immediate_operand" "")) | |
3669 | (set (match_operand:SI 4 "register_operand" "") | |
3670 | (const_int 0)) | |
3671 | (set (match_dup 0) | |
3672 | (plus:SI (match_dup 0) | |
3673 | (match_dup 2))) | |
3674 | (set (match_dup 1) | |
3675 | (plus:SI (match_dup 1) | |
3676 | (match_dup 2)))])] | |
3677 | "" | |
3678 | " | |
3679 | { | |
3680 | if (GET_CODE (operands[2]) != CONST_INT) | |
3681 | FAIL; | |
3682 | operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); | |
3683 | operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); | |
3684 | operands[4] = gen_reg_rtx (SImode); | |
3685 | }") | |
3686 | ||
3687 | (define_insn "" | |
3688 | [(set (mem:BLK (match_operand:SI 0 "register_operand" "D")) | |
3689 | (mem:BLK (match_operand:SI 1 "register_operand" "S"))) | |
3690 | (use (match_operand:SI 2 "immediate_operand" "n")) | |
3691 | (use (match_operand:SI 3 "immediate_operand" "i")) | |
3692 | (set (match_operand:SI 4 "register_operand" "c") | |
3693 | (const_int 0)) | |
3694 | (set (match_operand:SI 5 "register_operand" "=0") | |
3695 | (plus:SI (match_dup 0) | |
3696 | (match_dup 2))) | |
3697 | (set (match_operand:SI 7 "register_operand" "=1") | |
3698 | (plus:SI (match_dup 1) | |
3699 | (match_dup 2)))] | |
3700 | "" | |
3701 | "* | |
3702 | { | |
3703 | rtx xops[2]; | |
3704 | ||
3705 | if (GET_CODE (operands[2]) == CONST_INT) | |
3706 | { | |
3707 | if (INTVAL (operands[2]) & ~0x03) | |
3708 | { | |
3709 | xops[0] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) >> 2); | |
3710 | xops[1] = gen_rtx (REG, SImode, 2); | |
3711 | ||
3712 | output_asm_insn (AS2 (mov%L1,%0,%1), xops); | |
3713 | #ifdef INTEL_SYNTAX | |
3714 | output_asm_insn (\"rep movsd\", xops); | |
3715 | #else | |
0e52f7f5 | 3716 | output_asm_insn (\"rep\;movsl\", xops); |
886c62d1 JVA |
3717 | #endif |
3718 | } | |
3719 | if (INTVAL (operands[2]) & 0x02) | |
3720 | output_asm_insn (\"movsw\", operands); | |
3721 | if (INTVAL (operands[2]) & 0x01) | |
3722 | output_asm_insn (\"movsb\", operands); | |
3723 | } | |
3724 | else | |
3725 | abort (); | |
3726 | RET; | |
3727 | }") | |
3728 | ||
3729 | (define_expand "cmpstrsi" | |
3730 | [(parallel [(set (match_operand:QI 0 "general_operand" "") | |
c572e5ba | 3731 | (compare:CC |
886c62d1 JVA |
3732 | (mem:BLK (match_operand:BLK 1 "general_operand" "")) |
3733 | (mem:BLK (match_operand:BLK 2 "general_operand" "")))) | |
3734 | (use (match_operand:SI 3 "general_operand" "")) | |
3735 | (use (match_operand:SI 4 "immediate_operand" "")) | |
3736 | (clobber (match_dup 1)) | |
3737 | (clobber (match_dup 2)) | |
f76e3b05 | 3738 | (clobber (match_dup 3))])] |
886c62d1 JVA |
3739 | "" |
3740 | " | |
3741 | { | |
3742 | operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); | |
3743 | operands[2] = copy_to_mode_reg (SImode, XEXP (operands[2], 0)); | |
3744 | operands[3] = copy_to_mode_reg (SImode, operands[3]); | |
3745 | }") | |
3746 | ||
f76e3b05 JVA |
3747 | ;; memcmp recognizers. The `cmpsb' opcode does nothing if the count is |
3748 | ;; zero. Emit extra code to make sure that a zero-length compare is EQ. | |
3749 | ||
3750 | ;; ??? Most comparisons have a constant length, and it's therefore | |
3751 | ;; possible to know that the length is non-zero, and to avoid the extra | |
3752 | ;; code to handle zero-length compares. | |
3753 | ||
886c62d1 | 3754 | (define_insn "" |
f76e3b05 | 3755 | [(set (match_operand:QI 0 "general_operand" "=&q") |
c572e5ba JVA |
3756 | (compare:CC (mem:BLK (match_operand:SI 1 "general_operand" "S")) |
3757 | (mem:BLK (match_operand:SI 2 "general_operand" "D")))) | |
886c62d1 JVA |
3758 | (use (match_operand:SI 3 "general_operand" "c")) |
3759 | (use (match_operand:SI 4 "immediate_operand" "i")) | |
3760 | (clobber (match_dup 1)) | |
3761 | (clobber (match_dup 2)) | |
f76e3b05 | 3762 | (clobber (match_dup 3))] |
886c62d1 JVA |
3763 | "" |
3764 | "* | |
3765 | { | |
2aa8f23f JVA |
3766 | rtx xops[3], label; |
3767 | ||
3768 | label = gen_label_rtx (); | |
886c62d1 | 3769 | |
2aa8f23f | 3770 | output_asm_insn (AS2 (xor%B0,%0,%0), operands); |
886c62d1 | 3771 | output_asm_insn (\"repz\;cmps%B2\", operands); |
2aa8f23f | 3772 | output_asm_insn (\"je %l0\", &label); |
886c62d1 JVA |
3773 | |
3774 | xops[0] = operands[0]; | |
3775 | xops[1] = gen_rtx (MEM, QImode, | |
3776 | gen_rtx (PLUS, SImode, operands[1], constm1_rtx)); | |
3777 | xops[2] = gen_rtx (MEM, QImode, | |
3778 | gen_rtx (PLUS, SImode, operands[2], constm1_rtx)); | |
3779 | ||
3780 | output_asm_insn (AS2 (mov%B0,%1,%b0), xops); | |
3781 | output_asm_insn (AS2 (sub%B0,%2,%b0), xops); | |
2aa8f23f | 3782 | ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (label)); |
886c62d1 JVA |
3783 | RET; |
3784 | }") | |
3785 | ||
3786 | (define_insn "" | |
3787 | [(set (cc0) | |
c572e5ba JVA |
3788 | (compare:CC (mem:BLK (match_operand:SI 0 "general_operand" "S")) |
3789 | (mem:BLK (match_operand:SI 1 "general_operand" "D")))) | |
886c62d1 JVA |
3790 | (use (match_operand:SI 2 "general_operand" "c")) |
3791 | (use (match_operand:SI 3 "immediate_operand" "i")) | |
3792 | (clobber (match_dup 0)) | |
3793 | (clobber (match_dup 1)) | |
f76e3b05 | 3794 | (clobber (match_dup 2))] |
886c62d1 | 3795 | "" |
2aa8f23f JVA |
3796 | "* |
3797 | { | |
f76e3b05 JVA |
3798 | rtx xops[2]; |
3799 | ||
3800 | xops[0] = gen_rtx (REG, QImode, 0); | |
3801 | xops[1] = CONST0_RTX (QImode); | |
3802 | ||
3803 | output_asm_insn (AS2 (test%B0,%1,%0), xops); | |
2aa8f23f JVA |
3804 | return \"repz\;cmps%B2\"; |
3805 | }") | |
886c62d1 JVA |
3806 | |
3807 | (define_expand "ffssi2" | |
3808 | [(set (match_dup 2) | |
3809 | (plus:SI (ffs:SI (match_operand:SI 1 "general_operand" "")) | |
3810 | (const_int -1))) | |
3811 | (set (match_operand:SI 0 "general_operand" "") | |
3812 | (plus:SI (match_dup 2) (const_int 1)))] | |
3813 | "" | |
3814 | "operands[2] = gen_reg_rtx (SImode);") | |
3815 | ||
3816 | (define_insn "" | |
3817 | [(set (match_operand:SI 0 "general_operand" "=&r") | |
3818 | (plus:SI (ffs:SI (match_operand:SI 1 "general_operand" "rm")) | |
3819 | (const_int -1)))] | |
3820 | "" | |
3821 | "* | |
3822 | { | |
3823 | rtx xops[2]; | |
3824 | ||
3825 | xops[0] = operands[0]; | |
3826 | xops[1] = constm1_rtx; | |
3827 | output_asm_insn (AS2 (mov%L0,%1,%0), xops); | |
3828 | return AS2 (bsf%L0,%1,%0); | |
3829 | }") | |
3830 | ||
3831 | (define_expand "ffshi2" | |
3832 | [(set (match_dup 2) | |
3833 | (plus:HI (ffs:HI (match_operand:HI 1 "general_operand" "")) | |
3834 | (const_int -1))) | |
3835 | (set (match_operand:HI 0 "general_operand" "") | |
3836 | (plus:HI (match_dup 2) (const_int 1)))] | |
3837 | "" | |
3838 | "operands[2] = gen_reg_rtx (HImode);") | |
3839 | ||
3840 | (define_insn "" | |
3841 | [(set (match_operand:HI 0 "general_operand" "=&r") | |
3842 | (plus:HI (ffs:HI (match_operand:SI 1 "general_operand" "rm")) | |
3843 | (const_int -1)))] | |
3844 | "" | |
3845 | "* | |
3846 | { | |
3847 | rtx xops[2]; | |
3848 | ||
3849 | xops[0] = operands[0]; | |
3850 | xops[1] = constm1_rtx; | |
3851 | output_asm_insn (AS2 (mov%W0,%1,%0), xops); | |
3852 | return AS2 (bsf%W0,%1,%0); | |
3853 | }") | |
3854 | \f | |
3855 | ;; These patterns match the binary 387 instructions for addM3, subM3, | |
3856 | ;; mulM3 and divM3. There are three patterns for each of DFmode and | |
3857 | ;; SFmode. The first is the normal insn, the second the same insn but | |
3858 | ;; with one operand a conversion, and the third the same insn but with | |
3859 | ;; the other operand a conversion. The conversion may be SFmode or | |
3860 | ;; SImode if the target mode DFmode, but only SImode if the target mode | |
3861 | ;; is SFmode. | |
3862 | ||
3863 | (define_insn "" | |
3864 | [(set (match_operand:DF 0 "register_operand" "=f,f") | |
3865 | (match_operator:DF 3 "binary_387_op" | |
3866 | [(match_operand:DF 1 "general_operand" "0,fm") | |
3867 | (match_operand:DF 2 "general_operand" "fm,0")]))] | |
3868 | "TARGET_80387" | |
3869 | "* return (char *) output_387_binary_op (insn, operands);") | |
3870 | ||
3871 | (define_insn "" | |
3872 | [(set (match_operand:DF 0 "register_operand" "=f,f") | |
3873 | (match_operator:DF 3 "binary_387_op" | |
3874 | [(float:DF (match_operand:SI 1 "general_operand" "m,!*r")) | |
3875 | (match_operand:DF 2 "general_operand" "0,0")]))] | |
3876 | "TARGET_80387" | |
3877 | "* return (char *) output_387_binary_op (insn, operands);") | |
3878 | ||
3879 | (define_insn "" | |
3880 | [(set (match_operand:DF 0 "register_operand" "=f,f,f") | |
3881 | (match_operator:DF 3 "binary_387_op" | |
3882 | [(float_extend:DF (match_operand:SF 1 "general_operand" "fm,!*r,0")) | |
3883 | (match_operand:DF 2 "general_operand" "0,0,f")]))] | |
3884 | "TARGET_80387" | |
3885 | "* return (char *) output_387_binary_op (insn, operands);") | |
3886 | ||
3887 | (define_insn "" | |
3888 | [(set (match_operand:DF 0 "register_operand" "=f,f") | |
3889 | (match_operator:DF 3 "binary_387_op" | |
3890 | [(match_operand:DF 1 "general_operand" "0,0") | |
3891 | (float:DF (match_operand:SI 2 "general_operand" "m,!*r"))]))] | |
3892 | "TARGET_80387" | |
3893 | "* return (char *) output_387_binary_op (insn, operands);") | |
3894 | ||
3895 | (define_insn "" | |
3896 | [(set (match_operand:DF 0 "register_operand" "=f,f,f") | |
3897 | (match_operator:DF 3 "binary_387_op" | |
3898 | [(match_operand:DF 1 "general_operand" "0,0,f") | |
3899 | (float_extend:DF | |
3900 | (match_operand:SF 2 "general_operand" "fm,!*r,0"))]))] | |
3901 | "TARGET_80387" | |
3902 | "* return (char *) output_387_binary_op (insn, operands);") | |
3903 | ||
3904 | (define_insn "" | |
3905 | [(set (match_operand:SF 0 "register_operand" "=f,f") | |
3906 | (match_operator:SF 3 "binary_387_op" | |
3907 | [(match_operand:SF 1 "general_operand" "0,fm") | |
3908 | (match_operand:SF 2 "general_operand" "fm,0")]))] | |
3909 | "TARGET_80387" | |
3910 | "* return (char *) output_387_binary_op (insn, operands);") | |
3911 | ||
3912 | (define_insn "" | |
3913 | [(set (match_operand:SF 0 "register_operand" "=f,f") | |
3914 | (match_operator:SF 3 "binary_387_op" | |
3915 | [(float:SF (match_operand:SI 1 "general_operand" "m,!*r")) | |
3916 | (match_operand:SF 2 "general_operand" "0,0")]))] | |
3917 | "TARGET_80387" | |
3918 | "* return (char *) output_387_binary_op (insn, operands);") | |
3919 | ||
3920 | (define_insn "" | |
3921 | [(set (match_operand:SF 0 "register_operand" "=f,f") | |
3922 | (match_operator:SF 3 "binary_387_op" | |
3923 | [(match_operand:SF 1 "general_operand" "0,0") | |
3924 | (float:SF (match_operand:SI 2 "general_operand" "m,!*r"))]))] | |
3925 | "TARGET_80387" | |
3926 | "* return (char *) output_387_binary_op (insn, operands);") | |
3927 | \f | |
19c3fc24 RS |
3928 | (define_expand "strlensi" |
3929 | [(parallel [(set (match_dup 4) | |
3930 | (unspec:SI [(mem:BLK (match_operand:BLK 1 "general_operand" "")) | |
3931 | (match_operand:QI 2 "register_operand" "") | |
3932 | (match_operand:SI 3 "immediate_operand" "")] 0)) | |
3933 | (clobber (match_dup 1))]) | |
3934 | (set (match_dup 5) | |
3935 | (not:SI (match_dup 4))) | |
3936 | (set (match_operand:SI 0 "register_operand" "") | |
3937 | (minus:SI (match_dup 5) | |
3938 | (const_int 1)))] | |
3939 | "" | |
3940 | " | |
3941 | { | |
3942 | operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); | |
3943 | operands[4] = gen_reg_rtx (SImode); | |
3944 | operands[5] = gen_reg_rtx (SImode); | |
3945 | }") | |
3946 | ||
3947 | (define_insn "" | |
3948 | [(set (match_operand:SI 0 "register_operand" "=&c") | |
3949 | (unspec:SI [(mem:BLK (match_operand:SI 1 "register_operand" "D")) | |
3950 | (match_operand:QI 2 "register_operand" "a") | |
3951 | (match_operand:SI 3 "immediate_operand" "i")] 0)) | |
3952 | (clobber (match_dup 1))] | |
3953 | "" | |
3954 | "* | |
3955 | { | |
3956 | rtx xops[2]; | |
3957 | ||
3958 | xops[0] = operands[0]; | |
3959 | xops[1] = constm1_rtx; | |
3960 | output_asm_insn (AS2 (mov%L0,%1,%0), xops); | |
3961 | return \"repnz\;scas%B2\"; | |
3962 | }") | |
3963 | \f | |
886c62d1 JVA |
3964 | ;;- Local variables: |
3965 | ;;- mode:emacs-lisp | |
3966 | ;;- comment-start: ";;- " | |
3967 | ;;- eval: (set-syntax-table (copy-sequence (syntax-table))) | |
3968 | ;;- eval: (modify-syntax-entry ?[ "(]") | |
3969 | ;;- eval: (modify-syntax-entry ?] ")[") | |
3970 | ;;- eval: (modify-syntax-entry ?{ "(}") | |
3971 | ;;- eval: (modify-syntax-entry ?} "){") | |
3972 | ;;- End: |