|
|
1.1 root 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:
22: ;; Attribute specifications
23:
24: ;; Classify each instruction as to the precision control it requires.
25: (define_attr "fppc" "none,single,double,conflict"
26: (cond
27: [(match_operand:DF 0 "" "") (const_string "double")
28: (match_operand:SF 0 "" "") (const_string "single")]
29: (const_string "none")))
30:
31: ;; The original PO technology requires these to be ordered by speed,
32: ;; so that assigner will pick the fastest.
33:
34: ;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
35:
36: ;; Macro #define NOTICE_UPDATE_CC in file i386.h handles condition code
37: ;; updates for most instructions.
38:
39: ;; Macro REG_CLASS_FROM_LETTER in file i386.h defines the register
40: ;; constraint letters.
41:
42: ;; the special asm out single letter directives following a '%' are:
43: ;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of
44: ;; operands[1].
45: ;; 'L' Print the opcode suffix for a 32-bit integer opcode.
46: ;; 'W' Print the opcode suffix for a 16-bit integer opcode.
47: ;; 'B' Print the opcode suffix for an 8-bit integer opcode.
48: ;; 'S' Print the opcode suffix for a 32-bit float opcode.
49: ;; 'Q' Print the opcode suffix for a 64-bit float opcode.
50:
51: ;; 'b' Print the QImode name of the register for the indicated operand.
52: ;; %b0 would print %al if operands[0] is reg 0.
53: ;; 'w' Likewise, print the HImode name of the register.
54: ;; 'k' Likewise, print the SImode name of the register.
55: ;; 'h' Print the QImode name for a "high" register, either ah, bh, ch or dh.
56: ;; 'y' Print "st(0)" instead of "st" as a register.
57: ;; 'T' Print the opcode suffix for an 80-bit extended real XFmode float opcode.
58:
59: ;; UNSPEC usage:
60: ;; 0 This is a `scas' operation. The mode of the UNSPEC is always SImode.
61: ;; operand 0 is the memory address to scan.
62: ;; operand 1 is a register containing the value to scan for. The mode
63: ;; of the scas opcode will be the same as the mode of this operand.
64: ;; operand 2 is the known alignment of operand 0.
65: ;; 1 This is a `sin' operation. The mode of the UNSPEC is MODE_FLOAT.
66: ;; operand 0 is the argument for `sin'.
67: ;; 2 This is a `cos' operation. The mode of the UNSPEC is MODE_FLOAT.
68: ;; operand 0 is the argument for `cos'.
69:
70: ;; "movl MEM,REG / testl REG,REG" is faster on a 486 than "cmpl $0,MEM".
71: ;; But restricting MEM here would mean that gcc could not remove a redundant
72: ;; test in cases like "incl MEM / je TARGET".
73: ;;
74: ;; We don't want to allow a constant operand for test insns because
75: ;; (set (cc0) (const_int foo)) has no mode information. Such insns will
76: ;; be folded while optimizing anyway.
77:
78: ;; All test insns have expanders that save the operands away without
79: ;; actually generating RTL. The bCOND or sCOND (emitted immediately
80: ;; after the tstM or cmp) will actually emit the tstM or cmpM.
81:
82: (define_insn "tstsi_1"
83: [(set (cc0)
84: (match_operand:SI 0 "nonimmediate_operand" "rm"))]
85: ""
86: "*
87: {
88: if (REG_P (operands[0]))
89: return AS2 (test%L0,%0,%0);
90:
91: operands[1] = const0_rtx;
92: return AS2 (cmp%L0,%1,%0);
93: }")
94:
95: (define_expand "tstsi"
96: [(set (cc0)
97: (match_operand:SI 0 "nonimmediate_operand" ""))]
98: ""
99: "
100: {
101: i386_compare_gen = gen_tstsi_1;
102: i386_compare_op0 = operands[0];
103: DONE;
104: }")
105:
106: (define_insn "tsthi_1"
107: [(set (cc0)
108: (match_operand:HI 0 "nonimmediate_operand" "rm"))]
109: ""
110: "*
111: {
112: if (REG_P (operands[0]))
113: return AS2 (test%W0,%0,%0);
114:
115: operands[1] = const0_rtx;
116: return AS2 (cmp%W0,%1,%0);
117: }")
118:
119: (define_expand "tsthi"
120: [(set (cc0)
121: (match_operand:HI 0 "nonimmediate_operand" ""))]
122: ""
123: "
124: {
125: i386_compare_gen = gen_tsthi_1;
126: i386_compare_op0 = operands[0];
127: DONE;
128: }")
129:
130: (define_insn "tstqi_1"
131: [(set (cc0)
132: (match_operand:QI 0 "nonimmediate_operand" "qm"))]
133: ""
134: "*
135: {
136: if (REG_P (operands[0]))
137: return AS2 (test%B0,%0,%0);
138:
139: operands[1] = const0_rtx;
140: return AS2 (cmp%B0,%1,%0);
141: }")
142:
143: (define_expand "tstqi"
144: [(set (cc0)
145: (match_operand:QI 0 "nonimmediate_operand" ""))]
146: ""
147: "
148: {
149: i386_compare_gen = gen_tstqi_1;
150: i386_compare_op0 = operands[0];
151: DONE;
152: }")
153:
154: (define_insn "tstsf_cc"
155: [(set (cc0)
156: (match_operand:SF 0 "register_operand" "f"))
157: (clobber (match_scratch:HI 1 "=a"))]
158: "TARGET_80387 && ! TARGET_IEEE_FP"
159: "*
160: {
161: if (! STACK_TOP_P (operands[0]))
162: abort ();
163:
164: output_asm_insn (\"ftst\", operands);
165:
166: if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
167: output_asm_insn (AS1 (fstp,%y0), operands);
168:
169: return (char *) output_fp_cc0_set (insn);
170: }"
171: [(set_attr "fppc" "conflict")])
172:
173: ;; Don't generate tstsf if generating IEEE code, since the `ftst' opcode
174: ;; isn't IEEE compliant.
175:
176: (define_expand "tstsf"
177: [(parallel [(set (cc0)
178: (match_operand:SF 0 "register_operand" ""))
179: (clobber (match_scratch:HI 1 ""))])]
180: "TARGET_80387 && ! TARGET_IEEE_FP"
181: "
182: {
183: i386_compare_gen = gen_tstsf_cc;
184: i386_compare_op0 = operands[0];
185: DONE;
186: }")
187:
188: (define_insn "tstdf_cc"
189: [(set (cc0)
190: (match_operand:DF 0 "register_operand" "f"))
191: (clobber (match_scratch:HI 1 "=a"))]
192: "TARGET_80387 && ! TARGET_IEEE_FP"
193: "*
194: {
195: if (! STACK_TOP_P (operands[0]))
196: abort ();
197:
198: output_asm_insn (\"ftst\", operands);
199:
200: if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
201: output_asm_insn (AS1 (fstp,%y0), operands);
202:
203: return (char *) output_fp_cc0_set (insn);
204: }"
205: [(set_attr "fppc" "none")])
206:
207: ;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode
208: ;; isn't IEEE compliant.
209:
210: (define_expand "tstdf"
211: [(parallel [(set (cc0)
212: (match_operand:DF 0 "register_operand" ""))
213: (clobber (match_scratch:HI 1 ""))])]
214: "TARGET_80387 && ! TARGET_IEEE_FP"
215: "
216: {
217: i386_compare_gen = gen_tstdf_cc;
218: i386_compare_op0 = operands[0];
219: DONE;
220: }")
221:
222: (define_insn "tstxf_cc"
223: [(set (cc0)
224: (match_operand:XF 0 "register_operand" "f"))
225: (clobber (match_scratch:HI 1 "=a"))]
226: "TARGET_80387 && ! TARGET_IEEE_FP"
227: "*
228: {
229: if (! STACK_TOP_P (operands[0]))
230: abort ();
231:
232: output_asm_insn (\"ftst\", operands);
233:
234: if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
235: output_asm_insn (AS1 (fstp,%y0), operands);
236:
237: return (char *) output_fp_cc0_set (insn);
238: }")
239:
240: ;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode
241: ;; isn't IEEE compliant.
242:
243: (define_expand "tstxf"
244: [(parallel [(set (cc0)
245: (match_operand:XF 0 "register_operand" ""))
246: (clobber (match_scratch:HI 1 ""))])]
247: "TARGET_80387 && ! TARGET_IEEE_FP"
248: "
249: {
250: i386_compare_gen = gen_tstxf_cc;
251: i386_compare_op0 = operands[0];
252: DONE;
253: }")
254:
255: ;;- compare instructions. See comments above tstM patterns about
256: ;; expansion of these insns.
257:
258: (define_insn "cmpsi_1"
259: [(set (cc0)
260: (compare (match_operand:SI 0 "nonimmediate_operand" "mr,r")
261: (match_operand:SI 1 "general_operand" "ri,mr")))]
262: "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
263: "*
264: {
265: if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM)
266: {
267: cc_status.flags |= CC_REVERSED;
268: return AS2 (cmp%L0,%0,%1);
269: }
270: return AS2 (cmp%L0,%1,%0);
271: }")
272:
273: (define_expand "cmpsi"
274: [(set (cc0)
275: (compare (match_operand:SI 0 "nonimmediate_operand" "")
276: (match_operand:SI 1 "general_operand" "")))]
277: ""
278: "
279: {
280: if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
281: operands[0] = force_reg (SImode, operands[0]);
282:
283: i386_compare_gen = gen_cmpsi_1;
284: i386_compare_op0 = operands[0];
285: i386_compare_op1 = operands[1];
286: DONE;
287: }")
288:
289: (define_insn "cmphi_1"
290: [(set (cc0)
291: (compare (match_operand:HI 0 "nonimmediate_operand" "mr,r")
292: (match_operand:HI 1 "general_operand" "ri,mr")))]
293: "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
294: "*
295: {
296: if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM)
297: {
298: cc_status.flags |= CC_REVERSED;
299: return AS2 (cmp%W0,%0,%1);
300: }
301: return AS2 (cmp%W0,%1,%0);
302: }")
303:
304: (define_expand "cmphi"
305: [(set (cc0)
306: (compare (match_operand:HI 0 "nonimmediate_operand" "")
307: (match_operand:HI 1 "general_operand" "")))]
308: ""
309: "
310: {
311: if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
312: operands[0] = force_reg (HImode, operands[0]);
313:
314: i386_compare_gen = gen_cmphi_1;
315: i386_compare_op0 = operands[0];
316: i386_compare_op1 = operands[1];
317: DONE;
318: }")
319:
320: (define_insn "cmpqi_1"
321: [(set (cc0)
322: (compare (match_operand:QI 0 "nonimmediate_operand" "q,mq")
323: (match_operand:QI 1 "general_operand" "qm,nq")))]
324: "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
325: "*
326: {
327: if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM)
328: {
329: cc_status.flags |= CC_REVERSED;
330: return AS2 (cmp%B0,%0,%1);
331: }
332: return AS2 (cmp%B0,%1,%0);
333: }")
334:
335: (define_expand "cmpqi"
336: [(set (cc0)
337: (compare (match_operand:QI 0 "nonimmediate_operand" "")
338: (match_operand:QI 1 "general_operand" "")))]
339: ""
340: "
341: {
342: if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
343: operands[0] = force_reg (QImode, operands[0]);
344:
345: i386_compare_gen = gen_cmpqi_1;
346: i386_compare_op0 = operands[0];
347: i386_compare_op1 = operands[1];
348: DONE;
349: }")
350:
351: ;; These implement float point compares. For each of DFmode and
352: ;; SFmode, there is the normal insn, and an insn where the second operand
353: ;; is converted to the desired mode.
354:
355: (define_insn ""
356: [(set (cc0)
357: (match_operator 2 "VOIDmode_compare_op"
358: [(match_operand:XF 0 "nonimmediate_operand" "f")
359: (match_operand:XF 1 "nonimmediate_operand" "f")]))
360: (clobber (match_scratch:HI 3 "=a"))]
361: "TARGET_80387
362: && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
363: "* return (char *) output_float_compare (insn, operands);"
364: [(set_attr "fppc" "conflict")])
365:
366: (define_insn ""
367: [(set (cc0)
368: (match_operator 2 "VOIDmode_compare_op"
369: [(match_operand:XF 0 "register_operand" "f")
370: (float:XF
371: (match_operand:SI 1 "nonimmediate_operand" "rm"))]))
372: (clobber (match_scratch:HI 3 "=a"))]
373: "TARGET_80387"
374: "* return (char *) output_float_compare (insn, operands);"
375: [(set_attr "fppc" "conflict")])
376:
377: (define_insn ""
378: [(set (cc0)
379: (match_operator 2 "VOIDmode_compare_op"
380: [(float:XF
381: (match_operand:SI 0 "nonimmediate_operand" "rm"))
382: (match_operand:XF 1 "register_operand" "f")]))
383: (clobber (match_scratch:HI 3 "=a"))]
384: "TARGET_80387"
385: "* return (char *) output_float_compare (insn, operands);"
386: [(set_attr "fppc" "conflict")])
387:
388: (define_insn ""
389: [(set (cc0)
390: (match_operator 2 "VOIDmode_compare_op"
391: [(match_operand:XF 0 "register_operand" "f")
392: (float_extend:XF
393: (match_operand:DF 1 "nonimmediate_operand" "fm"))]))
394: (clobber (match_scratch:HI 3 "=a"))]
395: "TARGET_80387"
396: "* return (char *) output_float_compare (insn, operands);"
397: [(set_attr "fppc" "conflict")])
398:
399: (define_insn ""
400: [(set (cc0)
401: (match_operator 2 "VOIDmode_compare_op"
402: [(match_operand:XF 0 "register_operand" "f")
403: (float_extend:XF
404: (match_operand:SF 1 "nonimmediate_operand" "fm"))]))
405: (clobber (match_scratch:HI 3 "=a"))]
406: "TARGET_80387"
407: "* return (char *) output_float_compare (insn, operands);"
408: [(set_attr "fppc" "conflict")])
409:
410: (define_insn ""
411: [(set (cc0)
412: (compare:CCFPEQ (match_operand:XF 0 "register_operand" "f")
413: (match_operand:XF 1 "register_operand" "f")))
414: (clobber (match_scratch:HI 2 "=a"))]
415: "TARGET_80387"
416: "* return (char *) output_float_compare (insn, operands);"
417: [(set_attr "fppc" "conflict")])
418:
419: (define_insn ""
420: [(set (cc0)
421: (match_operator 2 "VOIDmode_compare_op"
422: [(match_operand:DF 0 "nonimmediate_operand" "f,fm")
423: (match_operand:DF 1 "nonimmediate_operand" "fm,f")]))
424: (clobber (match_scratch:HI 3 "=a,a"))]
425: "TARGET_80387
426: && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
427: "* return (char *) output_float_compare (insn, operands);"
428: [(set_attr "fppc" "conflict")])
429:
430: (define_insn ""
431: [(set (cc0)
432: (match_operator 2 "VOIDmode_compare_op"
433: [(match_operand:DF 0 "register_operand" "f")
434: (float:DF
435: (match_operand:SI 1 "nonimmediate_operand" "rm"))]))
436: (clobber (match_scratch:HI 3 "=a"))]
437: "TARGET_80387"
438: "* return (char *) output_float_compare (insn, operands);"
439: [(set_attr "fppc" "conflict")])
440:
441: (define_insn ""
442: [(set (cc0)
443: (match_operator 2 "VOIDmode_compare_op"
444: [(float:DF
445: (match_operand:SI 0 "nonimmediate_operand" "rm"))
446: (match_operand:DF 1 "register_operand" "f")]))
447: (clobber (match_scratch:HI 3 "=a"))]
448: "TARGET_80387"
449: "* return (char *) output_float_compare (insn, operands);"
450: [(set_attr "fppc" "conflict")])
451:
452: (define_insn ""
453: [(set (cc0)
454: (match_operator 2 "VOIDmode_compare_op"
455: [(match_operand:DF 0 "register_operand" "f")
456: (float_extend:DF
457: (match_operand:SF 1 "nonimmediate_operand" "fm"))]))
458: (clobber (match_scratch:HI 3 "=a"))]
459: "TARGET_80387"
460: "* return (char *) output_float_compare (insn, operands);"
461: [(set_attr "fppc" "conflict")])
462:
463: (define_insn ""
464: [(set (cc0)
465: (match_operator 2 "VOIDmode_compare_op"
466: [(float_extend:DF
467: (match_operand:SF 0 "nonimmediate_operand" "fm"))
468: (match_operand:DF 1 "register_operand" "f")]))
469: (clobber (match_scratch:HI 3 "=a"))]
470: "TARGET_80387"
471: "* return (char *) output_float_compare (insn, operands);"
472: [(set_attr "fppc" "conflict")])
473:
474: (define_insn ""
475: [(set (cc0)
476: (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f")
477: (match_operand:DF 1 "register_operand" "f")))
478: (clobber (match_scratch:HI 2 "=a"))]
479: "TARGET_80387"
480: "* return (char *) output_float_compare (insn, operands);"
481: [(set_attr "fppc" "conflict")])
482:
483: ;; These two insns will never be generated by combine due to the mode of
484: ;; the COMPARE.
485: ;(define_insn ""
486: ; [(set (cc0)
487: ; (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f")
488: ; (float_extend:DF
489: ; (match_operand:SF 1 "register_operand" "f"))))
490: ; (clobber (match_scratch:HI 2 "=a"))]
491: ; "TARGET_80387"
492: ; "* return (char *) output_float_compare (insn, operands);")
493: ;
494: ;(define_insn ""
495: ; [(set (cc0)
496: ; (compare:CCFPEQ (float_extend:DF
497: ; (match_operand:SF 0 "register_operand" "f"))
498: ; (match_operand:DF 1 "register_operand" "f")))
499: ; (clobber (match_scratch:HI 2 "=a"))]
500: ; "TARGET_80387"
501: ; "* return (char *) output_float_compare (insn, operands);")
502:
503: (define_insn "cmpsf_cc_1"
504: [(set (cc0)
505: (match_operator 2 "VOIDmode_compare_op"
506: [(match_operand:SF 0 "nonimmediate_operand" "f,fm")
507: (match_operand:SF 1 "nonimmediate_operand" "fm,f")]))
508: (clobber (match_scratch:HI 3 "=a,a"))]
509: "TARGET_80387
510: && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
511: "* return (char *) output_float_compare (insn, operands);"
512: [(set_attr "fppc" "none")])
513:
514: (define_insn ""
515: [(set (cc0)
516: (match_operator 2 "VOIDmode_compare_op"
517: [(match_operand:SF 0 "register_operand" "f")
518: (float:SF
519: (match_operand:SI 1 "nonimmediate_operand" "rm"))]))
520: (clobber (match_scratch:HI 3 "=a"))]
521: "TARGET_80387"
522: "* return (char *) output_float_compare (insn, operands);"
523: [(set_attr "fppc" "none")])
524:
525: (define_insn ""
526: [(set (cc0)
527: (match_operator 2 "VOIDmode_compare_op"
528: [(float:SF
529: (match_operand:SI 0 "nonimmediate_operand" "rm"))
530: (match_operand:SF 1 "register_operand" "f")]))
531: (clobber (match_scratch:HI 3 "=a"))]
532: "TARGET_80387"
533: "* return (char *) output_float_compare (insn, operands);"
534: [(set_attr "fppc" "none")])
535:
536: (define_insn ""
537: [(set (cc0)
538: (compare:CCFPEQ (match_operand:SF 0 "register_operand" "f")
539: (match_operand:SF 1 "register_operand" "f")))
540: (clobber (match_scratch:HI 2 "=a"))]
541: "TARGET_80387"
542: "* return (char *) output_float_compare (insn, operands);"
543: [(set_attr "fppc" "none")])
544:
545: (define_expand "cmpxf"
546: [(set (cc0)
547: (compare (match_operand:XF 0 "register_operand" "")
548: (match_operand:XF 1 "nonimmediate_operand" "")))]
549: "TARGET_80387"
550: "
551: {
552: i386_compare_gen = gen_cmpxf_cc;
553: i386_compare_gen_eq = gen_cmpxf_ccfpeq;
554: i386_compare_op0 = operands[0];
555: i386_compare_op1 = operands[1];
556: DONE;
557: }")
558:
559: (define_expand "cmpdf"
560: [(set (cc0)
561: (compare (match_operand:DF 0 "register_operand" "")
562: (match_operand:DF 1 "nonimmediate_operand" "")))]
563: "TARGET_80387"
564: "
565: {
566: i386_compare_gen = gen_cmpdf_cc;
567: i386_compare_gen_eq = gen_cmpdf_ccfpeq;
568: i386_compare_op0 = operands[0];
569: i386_compare_op1 = operands[1];
570: DONE;
571: }")
572:
573: (define_expand "cmpsf"
574: [(set (cc0)
575: (compare (match_operand:SF 0 "register_operand" "")
576: (match_operand:SF 1 "nonimmediate_operand" "")))]
577: "TARGET_80387"
578: "
579: {
580: i386_compare_gen = gen_cmpsf_cc;
581: i386_compare_gen_eq = gen_cmpsf_ccfpeq;
582: i386_compare_op0 = operands[0];
583: i386_compare_op1 = operands[1];
584: DONE;
585: }")
586:
587: (define_expand "cmpxf_cc"
588: [(parallel [(set (cc0)
589: (compare (match_operand:XF 0 "register_operand" "")
590: (match_operand:XF 1 "register_operand" "")))
591: (clobber (match_scratch:HI 2 ""))])]
592: "TARGET_80387"
593: "")
594:
595: (define_expand "cmpxf_ccfpeq"
596: [(parallel [(set (cc0)
597: (compare:CCFPEQ (match_operand:XF 0 "register_operand" "")
598: (match_operand:XF 1 "register_operand" "")))
599: (clobber (match_scratch:HI 2 ""))])]
600: "TARGET_80387"
601: "
602: {
603: if (! register_operand (operands[1], XFmode))
604: operands[1] = copy_to_mode_reg (XFmode, operands[1]);
605: }")
606:
607: (define_expand "cmpdf_cc"
608: [(parallel [(set (cc0)
609: (compare (match_operand:DF 0 "register_operand" "")
610: (match_operand:DF 1 "register_operand" "")))
611: (clobber (match_scratch:HI 2 ""))])]
612: "TARGET_80387"
613: "")
614:
615: (define_expand "cmpdf_ccfpeq"
616: [(parallel [(set (cc0)
617: (compare:CCFPEQ (match_operand:DF 0 "register_operand" "")
618: (match_operand:DF 1 "register_operand" "")))
619: (clobber (match_scratch:HI 2 ""))])]
620: "TARGET_80387"
621: "
622: {
623: if (! register_operand (operands[1], DFmode))
624: operands[1] = copy_to_mode_reg (DFmode, operands[1]);
625: }")
626:
627: (define_expand "cmpsf_cc"
628: [(parallel [(set (cc0)
629: (compare (match_operand:SF 0 "register_operand" "")
630: (match_operand:SF 1 "register_operand" "")))
631: (clobber (match_scratch:HI 2 ""))])]
632: "TARGET_80387"
633: "")
634:
635: (define_expand "cmpsf_ccfpeq"
636: [(parallel [(set (cc0)
637: (compare:CCFPEQ (match_operand:SF 0 "register_operand" "")
638: (match_operand:SF 1 "register_operand" "")))
639: (clobber (match_scratch:HI 2 ""))])]
640: "TARGET_80387"
641: "
642: {
643: if (! register_operand (operands[1], SFmode))
644: operands[1] = copy_to_mode_reg (SFmode, operands[1]);
645: }")
646:
647: ;; logical compare
648:
649: (define_insn ""
650: [(set (cc0)
651: (and:SI (match_operand:SI 0 "general_operand" "%ro")
652: (match_operand:SI 1 "general_operand" "ri")))]
653: ""
654: "*
655: {
656: /* For small integers, we may actually use testb. */
657: if (GET_CODE (operands[1]) == CONST_INT
658: && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
659: && (! REG_P (operands[0]) || QI_REG_P (operands[0])))
660: {
661: /* We may set the sign bit spuriously. */
662:
663: if ((INTVAL (operands[1]) & ~0xff) == 0)
664: {
665: cc_status.flags |= CC_NOT_NEGATIVE;
666: return AS2 (test%B0,%1,%b0);
667: }
668:
669: if ((INTVAL (operands[1]) & ~0xff00) == 0)
670: {
671: cc_status.flags |= CC_NOT_NEGATIVE;
672: operands[1] = GEN_INT (INTVAL (operands[1]) >> 8);
673:
674: if (QI_REG_P (operands[0]))
675: return AS2 (test%B0,%1,%h0);
676: else
677: {
678: operands[0] = adj_offsettable_operand (operands[0], 1);
679: return AS2 (test%B0,%1,%b0);
680: }
681: }
682:
683: if (GET_CODE (operands[0]) == MEM
684: && (INTVAL (operands[1]) & ~0xff0000) == 0)
685: {
686: cc_status.flags |= CC_NOT_NEGATIVE;
687: operands[1] = GEN_INT (INTVAL (operands[1]) >> 16);
688: operands[0] = adj_offsettable_operand (operands[0], 2);
689: return AS2 (test%B0,%1,%b0);
690: }
691:
692: if (GET_CODE (operands[0]) == MEM
693: && (INTVAL (operands[1]) & ~0xff000000) == 0)
694: {
695: operands[1] = GEN_INT ((INTVAL (operands[1]) >> 24) & 0xff);
696: operands[0] = adj_offsettable_operand (operands[0], 3);
697: return AS2 (test%B0,%1,%b0);
698: }
699: }
700:
701: if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
702: return AS2 (test%L0,%1,%0);
703:
704: return AS2 (test%L1,%0,%1);
705: }")
706:
707: (define_insn ""
708: [(set (cc0)
709: (and:HI (match_operand:HI 0 "general_operand" "%ro")
710: (match_operand:HI 1 "general_operand" "ri")))]
711: ""
712: "*
713: {
714: if (GET_CODE (operands[1]) == CONST_INT
715: && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
716: && (! REG_P (operands[0]) || QI_REG_P (operands[0])))
717: {
718: if ((INTVAL (operands[1]) & 0xff00) == 0)
719: {
720: /* ??? This might not be necessary. */
721: if (INTVAL (operands[1]) & 0xffff0000)
722: operands[1] = GEN_INT (INTVAL (operands[1]) & 0xff);
723:
724: /* We may set the sign bit spuriously. */
725: cc_status.flags |= CC_NOT_NEGATIVE;
726: return AS2 (test%B0,%1,%b0);
727: }
728:
729: if ((INTVAL (operands[1]) & 0xff) == 0)
730: {
731: operands[1] = GEN_INT ((INTVAL (operands[1]) >> 8) & 0xff);
732:
733: if (QI_REG_P (operands[0]))
734: return AS2 (test%B0,%1,%h0);
735: else
736: {
737: operands[0] = adj_offsettable_operand (operands[0], 1);
738: return AS2 (test%B0,%1,%b0);
739: }
740: }
741: }
742:
743: if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
744: return AS2 (test%W0,%1,%0);
745:
746: return AS2 (test%W1,%0,%1);
747: }")
748:
749: (define_insn ""
750: [(set (cc0)
751: (and:QI (match_operand:QI 0 "general_operand" "%qm")
752: (match_operand:QI 1 "general_operand" "qi")))]
753: ""
754: "*
755: {
756: if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
757: return AS2 (test%B0,%1,%0);
758:
759: return AS2 (test%B1,%0,%1);
760: }")
761:
762: ;; move instructions.
763: ;; There is one for each machine mode,
764: ;; and each is preceded by a corresponding push-insn pattern
765: ;; (since pushes are not general_operands on the 386).
766:
767: (define_insn ""
768: [(set (match_operand:SI 0 "push_operand" "=<")
769: (match_operand:SI 1 "general_operand" "g"))]
770: "! TARGET_486"
771: "push%L0 %1")
772:
773: ;; On a 486, it is faster to move MEM to a REG and then push, rather than
774: ;; push MEM directly.
775:
776: (define_insn ""
777: [(set (match_operand:SI 0 "push_operand" "=<")
778: (match_operand:SI 1 "general_operand" "ri"))]
779: "TARGET_486"
780: "push%L0 %1")
781:
782: ;; General case of fullword move.
783:
784: ;; If generating PIC code and operands[1] is a symbolic CONST, emit a
785: ;; move to get the address of the symbolic object from the GOT.
786:
787: (define_expand "movsi"
788: [(set (match_operand:SI 0 "general_operand" "")
789: (match_operand:SI 1 "general_operand" ""))]
790: ""
791: "
792: {
793: extern int flag_pic;
794:
795: if (flag_pic && SYMBOLIC_CONST (operands[1]))
796: emit_pic_move (operands, SImode);
797: }")
798:
799: ;; On i486, incl reg is faster than movl $1,reg.
800:
801: (define_insn ""
802: [(set (match_operand:SI 0 "general_operand" "=g,r")
803: (match_operand:SI 1 "general_operand" "ri,m"))]
804: ""
805: "*
806: {
807: rtx link;
808: if (operands[1] == const0_rtx && REG_P (operands[0]))
809: return AS2 (xor%L0,%0,%0);
810:
811: if (operands[1] == const1_rtx
812: && (link = find_reg_note (insn, REG_WAS_0, 0))
813: /* Make sure the insn that stored the 0 is still present. */
814: && ! INSN_DELETED_P (XEXP (link, 0))
815: && GET_CODE (XEXP (link, 0)) != NOTE
816: /* Make sure cross jumping didn't happen here. */
817: && no_labels_between_p (XEXP (link, 0), insn)
818: /* Make sure the reg hasn't been clobbered. */
819: && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
820: /* Fastest way to change a 0 to a 1. */
821: return AS1 (inc%L0,%0);
822:
823: return AS2 (mov%L0,%1,%0);
824: }")
825:
826: (define_insn ""
827: [(set (match_operand:HI 0 "push_operand" "=<")
828: (match_operand:HI 1 "general_operand" "g"))]
829: ""
830: "push%W0 %1")
831:
832: ;; On i486, an incl and movl are both faster than incw and movw.
833:
834: (define_insn "movhi"
835: [(set (match_operand:HI 0 "general_operand" "=g,r")
836: (match_operand:HI 1 "general_operand" "ri,m"))]
837: ""
838: "*
839: {
840: rtx link;
841: if (REG_P (operands[0]) && operands[1] == const0_rtx)
842: return AS2 (xor%L0,%k0,%k0);
843:
844: if (REG_P (operands[0]) && operands[1] == const1_rtx
845: && (link = find_reg_note (insn, REG_WAS_0, 0))
846: /* Make sure the insn that stored the 0 is still present. */
847: && ! INSN_DELETED_P (XEXP (link, 0))
848: && GET_CODE (XEXP (link, 0)) != NOTE
849: /* Make sure cross jumping didn't happen here. */
850: && no_labels_between_p (XEXP (link, 0), insn)
851: /* Make sure the reg hasn't been clobbered. */
852: && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
853: /* Fastest way to change a 0 to a 1. */
854: return AS1 (inc%L0,%k0);
855:
856: if (REG_P (operands[0]))
857: {
858: if (REG_P (operands[1]))
859: return AS2 (mov%L0,%k1,%k0);
860: else if (CONSTANT_P (operands[1]))
861: return AS2 (mov%L0,%1,%k0);
862: }
863:
864: return AS2 (mov%W0,%1,%0);
865: }")
866:
867: (define_insn "movstricthi"
868: [(set (strict_low_part (match_operand:HI 0 "general_operand" "+g,r"))
869: (match_operand:HI 1 "general_operand" "ri,m"))]
870: ""
871: "*
872: {
873: rtx link;
874: if (operands[1] == const0_rtx && REG_P (operands[0]))
875: return AS2 (xor%W0,%0,%0);
876:
877: if (operands[1] == const1_rtx
878: && (link = find_reg_note (insn, REG_WAS_0, 0))
879: /* Make sure the insn that stored the 0 is still present. */
880: && ! INSN_DELETED_P (XEXP (link, 0))
881: && GET_CODE (XEXP (link, 0)) != NOTE
882: /* Make sure cross jumping didn't happen here. */
883: && no_labels_between_p (XEXP (link, 0), insn)
884: /* Make sure the reg hasn't been clobbered. */
885: && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
886: /* Fastest way to change a 0 to a 1. */
887: return AS1 (inc%W0,%0);
888:
889: return AS2 (mov%W0,%1,%0);
890: }")
891:
892: ;; emit_push_insn when it calls move_by_pieces
893: ;; requires an insn to "push a byte".
894: ;; But actually we use pushw, which has the effect of rounding
895: ;; the amount pushed up to a halfword.
896: (define_insn ""
897: [(set (match_operand:QI 0 "push_operand" "=<")
898: (match_operand:QI 1 "general_operand" "q"))]
899: ""
900: "*
901: {
902: operands[1] = gen_rtx (REG, HImode, REGNO (operands[1]));
903: return AS1 (push%W0,%1);
904: }")
905:
906: ;; On i486, incb reg is faster than movb $1,reg.
907:
908: ;; ??? Do a recognizer for zero_extract that looks just like this, but reads
909: ;; or writes %ah, %bh, %ch, %dh.
910:
911: (define_insn "movqi"
912: [(set (match_operand:QI 0 "general_operand" "=q,*r,qm")
913: (match_operand:QI 1 "general_operand" "*g,q,qn"))]
914: ""
915: "*
916: {
917: rtx link;
918: if (operands[1] == const0_rtx && REG_P (operands[0]))
919: return AS2 (xor%B0,%0,%0);
920:
921: if (operands[1] == const1_rtx
922: && (link = find_reg_note (insn, REG_WAS_0, 0))
923: /* Make sure the insn that stored the 0 is still present. */
924: && ! INSN_DELETED_P (XEXP (link, 0))
925: && GET_CODE (XEXP (link, 0)) != NOTE
926: /* Make sure cross jumping didn't happen here. */
927: && no_labels_between_p (XEXP (link, 0), insn)
928: /* Make sure the reg hasn't been clobbered. */
929: && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
930: /* Fastest way to change a 0 to a 1. */
931: return AS1 (inc%B0,%0);
932:
933: /* If mov%B0 isn't allowed for one of these regs, use mov%L0. */
934: if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1]))
935: return (AS2 (mov%L0,%k1,%k0));
936:
937: return (AS2 (mov%B0,%1,%0));
938: }")
939:
940: ;; If it becomes necessary to support movstrictqi into %esi or %edi,
941: ;; use the insn sequence:
942: ;;
943: ;; shrdl $8,srcreg,dstreg
944: ;; rorl $24,dstreg
945: ;;
946: ;; If operands[1] is a constant, then an andl/orl sequence would be
947: ;; faster.
948:
949: (define_insn "movstrictqi"
950: [(set (strict_low_part (match_operand:QI 0 "general_operand" "+qm,q"))
951: (match_operand:QI 1 "general_operand" "*qn,m"))]
952: ""
953: "*
954: {
955: rtx link;
956: if (operands[1] == const0_rtx && REG_P (operands[0]))
957: return AS2 (xor%B0,%0,%0);
958:
959: if (operands[1] == const1_rtx
960: && (link = find_reg_note (insn, REG_WAS_0, 0))
961: /* Make sure the insn that stored the 0 is still present. */
962: && ! INSN_DELETED_P (XEXP (link, 0))
963: && GET_CODE (XEXP (link, 0)) != NOTE
964: /* Make sure cross jumping didn't happen here. */
965: && no_labels_between_p (XEXP (link, 0), insn)
966: /* Make sure the reg hasn't been clobbered. */
967: && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
968: /* Fastest way to change a 0 to a 1. */
969: return AS1 (inc%B0,%0);
970:
971: /* If mov%B0 isn't allowed for one of these regs, use mov%L0. */
972: if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1]))
973: {
974: abort ();
975: return (AS2 (mov%L0,%k1,%k0));
976: }
977:
978: return AS2 (mov%B0,%1,%0);
979: }")
980:
981: (define_insn ""
982: [(set (match_operand:SF 0 "push_operand" "=<,<")
983: (match_operand:SF 1 "general_operand" "gF,f"))]
984: ""
985: "*
986: {
987: if (STACK_REG_P (operands[1]))
988: {
989: rtx xops[3];
990:
991: if (! STACK_TOP_P (operands[1]))
992: abort ();
993:
994: xops[0] = AT_SP (SFmode);
995: xops[1] = GEN_INT (4);
996: xops[2] = stack_pointer_rtx;
997:
998: output_asm_insn (AS2 (sub%L2,%1,%2), xops);
999:
1000: if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
1001: output_asm_insn (AS1 (fstp%S0,%0), xops);
1002: else
1003: output_asm_insn (AS1 (fst%S0,%0), xops);
1004: RET;
1005: }
1006: return AS1 (push%L1,%1);
1007: }"
1008: [(set_attr "fppc" "none")])
1009:
1010: ;; Allow MEM-MEM moves before reload. The reload class for such a
1011: ;; move will be ALL_REGS. PREFERRED_RELOAD_CLASS will narrow this to
1012: ;; GENERAL_REGS. For the purposes of regclass, prefer FLOAT_REGS.
1013:
1014: (define_insn "movsf"
1015: [(set (match_operand:SF 0 "general_operand" "=*rfm,*rf,f,!*rm")
1016: (match_operand:SF 1 "general_operand" "*rf,*rfm,fG,fF"))]
1017: ""
1018: "*
1019: {
1020: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
1021:
1022: /* First handle a `pop' insn or a `fld %st(0)' */
1023:
1024: if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]))
1025: {
1026: if (stack_top_dies)
1027: return AS1 (fstp,%y0);
1028: else
1029: return AS1 (fld,%y0);
1030: }
1031:
1032: /* Handle a transfer between the 387 and a 386 register */
1033:
1034: if (STACK_TOP_P (operands[0]) && NON_STACK_REG_P (operands[1]))
1035: {
1036: output_op_from_reg (operands[1], AS1 (fld%z0,%y1));
1037: RET;
1038: }
1039:
1040: if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0]))
1041: {
1042: output_to_reg (operands[0], stack_top_dies);
1043: RET;
1044: }
1045:
1046: /* Handle other kinds of writes from the 387 */
1047:
1048: if (STACK_TOP_P (operands[1]))
1049: {
1050: if (stack_top_dies)
1051: return AS1 (fstp%z0,%y0);
1052: else
1053: return AS1 (fst%z0,%y0);
1054: }
1055:
1056: /* Handle other kinds of reads to the 387 */
1057:
1058: if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
1059: return (char *) output_move_const_single (operands);
1060:
1061: if (STACK_TOP_P (operands[0]))
1062: return AS1 (fld%z1,%y1);
1063:
1064: /* Handle all SFmode moves not involving the 387 */
1065:
1066: return (char *) singlemove_string (operands);
1067: }"
1068: [(set_attr "fppc" "none")])
1069:
1070: ;;should change to handle the memory operands[1] without doing df push..
1071: (define_insn ""
1072: [(set (match_operand:DF 0 "push_operand" "=<,<")
1073: (match_operand:DF 1 "general_operand" "gF,f"))]
1074: ""
1075: "*
1076: {
1077: if (STACK_REG_P (operands[1]))
1078: {
1079: rtx xops[3];
1080:
1081: xops[0] = AT_SP (SFmode);
1082: xops[1] = GEN_INT (8);
1083: xops[2] = stack_pointer_rtx;
1084:
1085: output_asm_insn (AS2 (sub%L2,%1,%2), xops);
1086:
1087: if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
1088: output_asm_insn (AS1 (fstp%Q0,%0), xops);
1089: else
1090: output_asm_insn (AS1 (fst%Q0,%0), xops);
1091:
1092: RET;
1093: }
1094: else
1095: return (char *) output_move_double (operands);
1096: }"
1097: [(set_attr "fppc" "none")])
1098:
1099: (define_insn "swapdf"
1100: [(set (match_operand:DF 0 "register_operand" "f")
1101: (match_operand:DF 1 "register_operand" "f"))
1102: (set (match_dup 1)
1103: (match_dup 0))]
1104: ""
1105: "*
1106: {
1107: if (STACK_TOP_P (operands[0]))
1108: return AS1 (fxch,%1);
1109: else
1110: return AS1 (fxch,%0);
1111: }"
1112: [(set_attr "fppc" "none")])
1113:
1114: ;; Allow MEM-MEM moves before reload. The reload class for such a
1115: ;; move will be ALL_REGS. PREFERRED_RELOAD_CLASS will narrow this to
1116: ;; GENERAL_REGS. For the purposes of regclass, prefer FLOAT_REGS.
1117:
1118: (define_insn "movdf"
1119: [(set (match_operand:DF 0 "general_operand" "=*rfm,*rf,f,!*rm")
1120: (match_operand:DF 1 "general_operand" "*rf,*rfm,fG,fF"))]
1121: ""
1122: "*
1123: {
1124: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
1125:
1126: /* First handle a `pop' insn or a `fld %st(0)' */
1127:
1128: if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]))
1129: {
1130: if (stack_top_dies)
1131: return AS1 (fstp,%y0);
1132: else
1133: return AS1 (fld,%y0);
1134: }
1135:
1136: /* Handle a transfer between the 387 and a 386 register */
1137:
1138: if (STACK_TOP_P (operands[0]) && NON_STACK_REG_P (operands[1]))
1139: {
1140: output_op_from_reg (operands[1], AS1 (fld%z0,%y1));
1141: RET;
1142: }
1143:
1144: if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0]))
1145: {
1146: output_to_reg (operands[0], stack_top_dies);
1147: RET;
1148: }
1149:
1150: /* Handle other kinds of writes from the 387 */
1151:
1152: if (STACK_TOP_P (operands[1]))
1153: {
1154: if (stack_top_dies)
1155: return AS1 (fstp%z0,%y0);
1156: else
1157: return AS1 (fst%z0,%y0);
1158: }
1159:
1160: /* Handle other kinds of reads to the 387 */
1161:
1162: if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
1163: return (char *) output_move_const_single (operands);
1164:
1165: if (STACK_TOP_P (operands[0]))
1166: return AS1 (fld%z1,%y1);
1167:
1168: /* Handle all DFmode moves not involving the 387 */
1169:
1170: return (char *) output_move_double (operands);
1171: }"
1172: [(set_attr "fppc" "none")])
1173:
1174: (define_insn ""
1175: [(set (match_operand:XF 0 "push_operand" "=<,<")
1176: (match_operand:XF 1 "general_operand" "gF,f"))]
1177: ""
1178: "*
1179: {
1180: if (STACK_REG_P (operands[1]))
1181: {
1182: rtx xops[3];
1183:
1184: xops[0] = AT_SP (SFmode);
1185: xops[1] = GEN_INT (12);
1186: xops[2] = stack_pointer_rtx;
1187:
1188: output_asm_insn (AS2 (sub%L2,%1,%2), xops);
1189: output_asm_insn (AS1 (fstp%T0,%0), xops);
1190: if (! find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
1191: output_asm_insn (AS1 (fld%T0,%0), xops);
1192:
1193: RET;
1194: }
1195: else
1196: return (char *) output_move_double (operands);
1197: }")
1198:
1199: (define_insn "swapxf"
1200: [(set (match_operand:XF 0 "register_operand" "f")
1201: (match_operand:XF 1 "register_operand" "f"))
1202: (set (match_dup 1)
1203: (match_dup 0))]
1204: ""
1205: "*
1206: {
1207: if (STACK_TOP_P (operands[0]))
1208: return AS1 (fxch,%1);
1209: else
1210: return AS1 (fxch,%0);
1211: }")
1212:
1213: (define_insn "movxf"
1214: [(set (match_operand:XF 0 "general_operand" "=f,fm,!*rf,!*rm")
1215: (match_operand:XF 1 "general_operand" "fmG,f,*rfm,*rfF"))]
1216: ;; [(set (match_operand:XF 0 "general_operand" "=*rf,*rfm,f,!*rm")
1217: ;; (match_operand:XF 1 "general_operand" "*rfm,*rf,fG,fF"))]
1218: ""
1219: "*
1220: {
1221: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
1222:
1223: /* First handle a `pop' insn or a `fld %st(0)' */
1224:
1225: if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]))
1226: {
1227: if (stack_top_dies)
1228: return AS1 (fstp,%y0);
1229: else
1230: return AS1 (fld,%y0);
1231: }
1232:
1233: /* Handle a transfer between the 387 and a 386 register */
1234:
1235: if (STACK_TOP_P (operands[0]) && NON_STACK_REG_P (operands[1]))
1236: {
1237: output_op_from_reg (operands[1], AS1 (fld%z0,%y1));
1238: RET;
1239: }
1240:
1241: if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0]))
1242: {
1243: output_to_reg (operands[0], stack_top_dies);
1244: RET;
1245: }
1246:
1247: /* Handle other kinds of writes from the 387 */
1248:
1249: if (STACK_TOP_P (operands[1]))
1250: {
1251: output_asm_insn (AS1 (fstp%z0,%y0), operands);
1252: if (! stack_top_dies)
1253: return AS1 (fld%z0,%y0);
1254:
1255: RET;
1256: }
1257:
1258: /* Handle other kinds of reads to the 387 */
1259:
1260: if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
1261: return (char *) output_move_const_single (operands);
1262:
1263: if (STACK_TOP_P (operands[0]))
1264: return AS1 (fld%z1,%y1);
1265:
1266: /* Handle all XFmode moves not involving the 387 */
1267:
1268: return (char *) output_move_double (operands);
1269: }")
1270:
1271: (define_insn ""
1272: [(set (match_operand:DI 0 "push_operand" "=<")
1273: (match_operand:DI 1 "general_operand" "roiF"))]
1274: ""
1275: "*
1276: {
1277: return (char *) output_move_double (operands);
1278: }")
1279:
1280: (define_insn "movdi"
1281: [(set (match_operand:DI 0 "general_operand" "=r,rm")
1282: (match_operand:DI 1 "general_operand" "m,riF"))]
1283: ""
1284: "*
1285: {
1286: return (char *) output_move_double (operands);
1287: }")
1288:
1289: ;;- conversion instructions
1290: ;;- NONE
1291:
1292: ;;- zero extension instructions
1293: ;; See comments by `andsi' for when andl is faster than movzx.
1294:
1295: (define_insn "zero_extendhisi2"
1296: [(set (match_operand:SI 0 "general_operand" "=r")
1297: (zero_extend:SI
1298: (match_operand:HI 1 "nonimmediate_operand" "rm")))]
1299: ""
1300: "*
1301: {
1302: if ((TARGET_486 || REGNO (operands[0]) == 0)
1303: && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
1304: {
1305: rtx xops[2];
1306: xops[0] = operands[0];
1307: xops[1] = GEN_INT (0xffff);
1308: output_asm_insn (AS2 (and%L0,%1,%k0), xops);
1309: RET;
1310: }
1311:
1312: #ifdef INTEL_SYNTAX
1313: return AS2 (movzx,%1,%0);
1314: #else
1315: return AS2 (movz%W0%L0,%1,%0);
1316: #endif
1317: }")
1318:
1319: (define_insn "zero_extendqihi2"
1320: [(set (match_operand:HI 0 "general_operand" "=r")
1321: (zero_extend:HI
1322: (match_operand:QI 1 "nonimmediate_operand" "qm")))]
1323: ""
1324: "*
1325: {
1326: if ((TARGET_486 || REGNO (operands[0]) == 0)
1327: && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
1328: {
1329: rtx xops[2];
1330: xops[0] = operands[0];
1331: xops[1] = GEN_INT (0xff);
1332: output_asm_insn (AS2 (and%L0,%1,%k0), xops);
1333: RET;
1334: }
1335:
1336: #ifdef INTEL_SYNTAX
1337: return AS2 (movzx,%1,%0);
1338: #else
1339: return AS2 (movz%B0%W0,%1,%0);
1340: #endif
1341: }")
1342:
1343: (define_insn "zero_extendqisi2"
1344: [(set (match_operand:SI 0 "general_operand" "=r")
1345: (zero_extend:SI
1346: (match_operand:QI 1 "nonimmediate_operand" "qm")))]
1347: ""
1348: "*
1349: {
1350: if ((TARGET_486 || REGNO (operands[0]) == 0)
1351: && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
1352: {
1353: rtx xops[2];
1354: xops[0] = operands[0];
1355: xops[1] = GEN_INT (0xff);
1356: output_asm_insn (AS2 (and%L0,%1,%k0), xops);
1357: RET;
1358: }
1359:
1360: #ifdef INTEL_SYNTAX
1361: return AS2 (movzx,%1,%0);
1362: #else
1363: return AS2 (movz%B0%L0,%1,%0);
1364: #endif
1365: }")
1366:
1367: (define_insn "zero_extendsidi2"
1368: [(set (match_operand:DI 0 "register_operand" "=r")
1369: (zero_extend:DI
1370: (match_operand:SI 1 "register_operand" "0")))]
1371: ""
1372: "*
1373: {
1374: operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
1375: return AS2 (xor%L0,%0,%0);
1376: }")
1377:
1378: ;;- sign extension instructions
1379:
1380: (define_insn "extendsidi2"
1381: [(set (match_operand:DI 0 "register_operand" "=r")
1382: (sign_extend:DI
1383: (match_operand:SI 1 "register_operand" "0")))]
1384: ""
1385: "*
1386: {
1387: if (REGNO (operands[0]) == 0)
1388: {
1389: /* This used to be cwtl, but that extends HI to SI somehow. */
1390: #ifdef INTEL_SYNTAX
1391: return \"cdq\";
1392: #else
1393: return \"cltd\";
1394: #endif
1395: }
1396:
1397: operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
1398: output_asm_insn (AS2 (mov%L0,%0,%1), operands);
1399:
1400: operands[0] = GEN_INT (31);
1401: return AS2 (sar%L1,%0,%1);
1402: }")
1403:
1404: ;; Note that the i386 programmers' manual says that the opcodes
1405: ;; are named movsx..., but the assembler on Unix does not accept that.
1406: ;; We use what the Unix assembler expects.
1407:
1408: (define_insn "extendhisi2"
1409: [(set (match_operand:SI 0 "general_operand" "=r")
1410: (sign_extend:SI
1411: (match_operand:HI 1 "nonimmediate_operand" "rm")))]
1412: ""
1413: "*
1414: {
1415: if (REGNO (operands[0]) == 0
1416: && REG_P (operands[1]) && REGNO (operands[1]) == 0)
1417: #ifdef INTEL_SYNTAX
1418: return \"cwde\";
1419: #else
1420: return \"cwtl\";
1421: #endif
1422:
1423: #ifdef INTEL_SYNTAX
1424: return AS2 (movsx,%1,%0);
1425: #else
1426: return AS2 (movs%W0%L0,%1,%0);
1427: #endif
1428: }")
1429:
1430: (define_insn "extendqihi2"
1431: [(set (match_operand:HI 0 "general_operand" "=r")
1432: (sign_extend:HI
1433: (match_operand:QI 1 "nonimmediate_operand" "qm")))]
1434: ""
1435: "*
1436: {
1437: if (REGNO (operands[0]) == 0
1438: && REG_P (operands[1]) && REGNO (operands[1]) == 0)
1439: return \"cbtw\";
1440:
1441: #ifdef INTEL_SYNTAX
1442: return AS2 (movsx,%1,%0);
1443: #else
1444: return AS2 (movs%B0%W0,%1,%0);
1445: #endif
1446: }")
1447:
1448: (define_insn "extendqisi2"
1449: [(set (match_operand:SI 0 "general_operand" "=r")
1450: (sign_extend:SI
1451: (match_operand:QI 1 "nonimmediate_operand" "qm")))]
1452: ""
1453: "*
1454: {
1455: #ifdef INTEL_SYNTAX
1456: return AS2 (movsx,%1,%0);
1457: #else
1458: return AS2 (movs%B0%L0,%1,%0);
1459: #endif
1460: }")
1461:
1462: ;; Conversions between float and double.
1463:
1464: (define_insn "extendsfdf2"
1465: [(set (match_operand:DF 0 "general_operand" "=fm,f")
1466: (float_extend:DF
1467: (match_operand:SF 1 "general_operand" "f,fm")))]
1468: "TARGET_80387"
1469: "*
1470: {
1471: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
1472:
1473: if (NON_STACK_REG_P (operands[1]))
1474: {
1475: output_op_from_reg (operands[1], AS1 (fld%z0,%y1));
1476: RET;
1477: }
1478:
1479: if (NON_STACK_REG_P (operands[0]))
1480: {
1481: output_to_reg (operands[0], stack_top_dies);
1482: RET;
1483: }
1484:
1485: if (STACK_TOP_P (operands[0]))
1486: return AS1 (fld%z1,%y1);
1487:
1488: if (GET_CODE (operands[0]) == MEM)
1489: {
1490: if (stack_top_dies)
1491: return AS1 (fstp%z0,%y0);
1492: else
1493: return AS1 (fst%z0,%y0);
1494: }
1495:
1496: abort ();
1497: }")
1498:
1499: (define_insn "extenddfxf2"
1500: [(set (match_operand:XF 0 "general_operand" "=fm,f,f,!*r")
1501: (float_extend:XF
1502: (match_operand:DF 1 "general_operand" "f,fm,!*r,f")))]
1503: "TARGET_80387"
1504: "*
1505: {
1506: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
1507:
1508: if (NON_STACK_REG_P (operands[1]))
1509: {
1510: output_op_from_reg (operands[1], AS1 (fld%z0,%y1));
1511: RET;
1512: }
1513:
1514: if (NON_STACK_REG_P (operands[0]))
1515: {
1516: output_to_reg (operands[0], stack_top_dies);
1517: RET;
1518: }
1519:
1520: if (STACK_TOP_P (operands[0]))
1521: return AS1 (fld%z1,%y1);
1522:
1523: if (GET_CODE (operands[0]) == MEM)
1524: {
1525: output_asm_insn (AS1 (fstp%z0,%y0), operands);
1526: if (! stack_top_dies)
1527: return AS1 (fld%z0,%y0);
1528: RET;
1529: }
1530:
1531: abort ();
1532: }")
1533:
1534: (define_insn "extendsfxf2"
1535: [(set (match_operand:XF 0 "general_operand" "=fm,f,f,!*r")
1536: (float_extend:XF
1537: (match_operand:SF 1 "general_operand" "f,fm,!*r,f")))]
1538: "TARGET_80387"
1539: "*
1540: {
1541: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
1542:
1543: if (NON_STACK_REG_P (operands[1]))
1544: {
1545: output_op_from_reg (operands[1], AS1 (fld%z0,%y1));
1546: RET;
1547: }
1548:
1549: if (NON_STACK_REG_P (operands[0]))
1550: {
1551: output_to_reg (operands[0], stack_top_dies);
1552: RET;
1553: }
1554:
1555: if (STACK_TOP_P (operands[0]))
1556: return AS1 (fld%z1,%y1);
1557:
1558: if (GET_CODE (operands[0]) == MEM)
1559: {
1560: output_asm_insn (AS1 (fstp%z0,%y0), operands);
1561: if (! stack_top_dies)
1562: return AS1 (fld%z0,%y0);
1563: RET;
1564: }
1565:
1566: abort ();
1567: }")
1568:
1569: (define_expand "truncdfsf2"
1570: [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
1571: (float_truncate:SF
1572: (match_operand:DF 1 "register_operand" "")))
1573: (clobber (match_dup 2))])]
1574: "TARGET_80387"
1575: "
1576: {
1577: operands[2] = (rtx) assign_386_stack_local (SFmode, 0);
1578: }")
1579:
1580: ;; This cannot output into an f-reg because there is no way to be sure
1581: ;; of truncating in that case. Otherwise this is just like a simple move
1582: ;; insn. So we pretend we can output to a reg in order to get better
1583: ;; register preferencing, but we really use a stack slot.
1584:
1585: (define_insn ""
1586: [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m")
1587: (float_truncate:SF
1588: (match_operand:DF 1 "register_operand" "0,f")))
1589: (clobber (match_operand:SF 2 "memory_operand" "m,m"))]
1590: "TARGET_80387"
1591: "*
1592: {
1593: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
1594:
1595: if (GET_CODE (operands[0]) == MEM)
1596: {
1597: if (stack_top_dies)
1598: return AS1 (fstp%z0,%0);
1599: else
1600: return AS1 (fst%z0,%0);
1601: }
1602: else if (STACK_TOP_P (operands[0]))
1603: {
1604: output_asm_insn (AS1 (fstp%z2,%y2), operands);
1605: return AS1 (fld%z2,%y2);
1606: }
1607: else
1608: abort ();
1609: }"
1610: [(set_attr "fppc" "none")])
1611:
1612: (define_insn "truncxfsf2"
1613: [(set (match_operand:SF 0 "general_operand" "=m,!*r")
1614: (float_truncate:SF
1615: (match_operand:XF 1 "register_operand" "f,f")))]
1616: "TARGET_80387"
1617: "*
1618: {
1619: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
1620:
1621: if (NON_STACK_REG_P (operands[0]))
1622: {
1623: if (stack_top_dies == 0)
1624: {
1625: output_asm_insn (AS1 (fld,%y1), operands);
1626: stack_top_dies = 1;
1627: }
1628: output_to_reg (operands[0], stack_top_dies);
1629: RET;
1630: }
1631: else if (GET_CODE (operands[0]) == MEM)
1632: {
1633: if (stack_top_dies)
1634: return AS1 (fstp%z0,%0);
1635: else
1636: {
1637: output_asm_insn (AS1 (fld,%y1), operands);
1638: return AS1 (fstp%z0,%0);
1639: }
1640: }
1641: else
1642: abort ();
1643: }"
1644: [(set_attr "fppc" "none")])
1645:
1646: (define_insn "truncxfdf2"
1647: [(set (match_operand:DF 0 "general_operand" "=m,!*r")
1648: (float_truncate:DF
1649: (match_operand:XF 1 "register_operand" "f,f")))]
1650: "TARGET_80387"
1651: "*
1652: {
1653: int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
1654:
1655: if (NON_STACK_REG_P (operands[0]))
1656: {
1657: if (stack_top_dies == 0)
1658: {
1659: output_asm_insn (AS1 (fld,%y1), operands);
1660: stack_top_dies = 1;
1661: }
1662: output_to_reg (operands[0], stack_top_dies);
1663: RET;
1664: }
1665: else if (GET_CODE (operands[0]) == MEM)
1666: {
1667: if (stack_top_dies)
1668: return AS1 (fstp%z0,%0);
1669: else
1670: {
1671: output_asm_insn (AS1 (fld,%y1), operands);
1672: return AS1 (fstp%z0,%0);
1673: }
1674: }
1675: else
1676: abort ();
1677: }"
1678: [(set_attr "fppc" "none")])
1679:
1680:
1681: ;; The 387 requires that the stack top dies after converting to DImode.
1682:
1683: ;; Represent an unsigned conversion from SImode to MODE_FLOAT by first
1684: ;; doing a signed conversion to DImode, and then taking just the low
1685: ;; part.
1686:
1687: (define_expand "fixuns_truncxfsi2"
1688: [(set (match_dup 4)
1689: (match_operand:XF 1 "register_operand" ""))
1690: (parallel [(set (match_dup 2)
1691: (fix:DI (fix:XF (match_dup 4))))
1692: (clobber (match_dup 4))
1693: (clobber (match_dup 5))
1694: (clobber (match_dup 6))
1695: (clobber (match_scratch:SI 7 ""))])
1696: (set (match_operand:SI 0 "general_operand" "")
1697: (match_dup 3))]
1698: "TARGET_80387"
1699: "
1700: {
1701: operands[2] = gen_reg_rtx (DImode);
1702: operands[3] = gen_lowpart (SImode, operands[2]);
1703: operands[4] = gen_reg_rtx (XFmode);
1704: operands[5] = (rtx) assign_386_stack_local (SImode, 0);
1705: operands[6] = (rtx) assign_386_stack_local (SImode, 1);
1706: }")
1707:
1708: (define_expand "fixuns_truncdfsi2"
1709: [(set (match_dup 4)
1710: (match_operand:DF 1 "register_operand" ""))
1711: (parallel [(set (match_dup 2)
1712: (fix:DI (fix:DF (match_dup 4))))
1713: (clobber (match_dup 4))
1714: (clobber (match_dup 5))
1715: (clobber (match_dup 6))
1716: (clobber (match_scratch:SI 7 ""))])
1717: (set (match_operand:SI 0 "general_operand" "")
1718: (match_dup 3))]
1719: "TARGET_80387"
1720: "
1721: {
1722: operands[2] = gen_reg_rtx (DImode);
1723: operands[3] = gen_lowpart (SImode, operands[2]);
1724: operands[4] = gen_reg_rtx (DFmode);
1725: operands[5] = (rtx) assign_386_stack_local (SImode, 0);
1726: operands[6] = (rtx) assign_386_stack_local (SImode, 1);
1727: }")
1728:
1729: (define_expand "fixuns_truncsfsi2"
1730: [(set (match_dup 4)
1731: (match_operand:SF 1 "register_operand" ""))
1732: (parallel [(set (match_dup 2)
1733: (fix:DI (fix:SF (match_dup 4))))
1734: (clobber (match_dup 4))
1735: (clobber (match_dup 5))
1736: (clobber (match_dup 6))
1737: (clobber (match_scratch:SI 7 ""))])
1738: (set (match_operand:SI 0 "general_operand" "")
1739: (match_dup 3))]
1740: "TARGET_80387"
1741: "
1742: {
1743: operands[2] = gen_reg_rtx (DImode);
1744: operands[3] = gen_lowpart (SImode, operands[2]);
1745: operands[4] = gen_reg_rtx (SFmode);
1746: operands[5] = (rtx) assign_386_stack_local (SImode, 0);
1747: operands[6] = (rtx) assign_386_stack_local (SImode, 1);
1748: }")
1749:
1750: ;; Signed conversion to DImode.
1751:
1752: (define_expand "fix_truncxfdi2"
1753: [(set (match_dup 2)
1754: (match_operand:XF 1 "register_operand" ""))
1755: (parallel [(set (match_operand:DI 0 "general_operand" "")
1756: (fix:DI (fix:XF (match_dup 2))))
1757: (clobber (match_dup 2))
1758: (clobber (match_dup 3))
1759: (clobber (match_dup 4))
1760: (clobber (match_scratch:SI 5 ""))])]
1761: "TARGET_80387"
1762: "
1763: {
1764: operands[1] = copy_to_mode_reg (XFmode, operands[1]);
1765: operands[2] = gen_reg_rtx (XFmode);
1766: operands[3] = (rtx) assign_386_stack_local (SImode, 0);
1767: operands[4] = (rtx) assign_386_stack_local (SImode, 1);
1768: }")
1769:
1770: (define_expand "fix_truncdfdi2"
1771: [(set (match_dup 2)
1772: (match_operand:DF 1 "register_operand" ""))
1773: (parallel [(set (match_operand:DI 0 "general_operand" "")
1774: (fix:DI (fix:DF (match_dup 2))))
1775: (clobber (match_dup 2))
1776: (clobber (match_dup 3))
1777: (clobber (match_dup 4))
1778: (clobber (match_scratch:SI 5 ""))])]
1779: "TARGET_80387"
1780: "
1781: {
1782: operands[1] = copy_to_mode_reg (DFmode, operands[1]);
1783: operands[2] = gen_reg_rtx (DFmode);
1784: operands[3] = (rtx) assign_386_stack_local (SImode, 0);
1785: operands[4] = (rtx) assign_386_stack_local (SImode, 1);
1786: }")
1787:
1788: (define_expand "fix_truncsfdi2"
1789: [(set (match_dup 2)
1790: (match_operand:SF 1 "register_operand" ""))
1791: (parallel [(set (match_operand:DI 0 "general_operand" "")
1792: (fix:DI (fix:SF (match_dup 2))))
1793: (clobber (match_dup 2))
1794: (clobber (match_dup 3))
1795: (clobber (match_dup 4))
1796: (clobber (match_scratch:SI 5 ""))])]
1797: "TARGET_80387"
1798: "
1799: {
1800: operands[1] = copy_to_mode_reg (SFmode, operands[1]);
1801: operands[2] = gen_reg_rtx (SFmode);
1802: operands[3] = (rtx) assign_386_stack_local (SImode, 0);
1803: operands[4] = (rtx) assign_386_stack_local (SImode, 1);
1804: }")
1805:
1806: ;; These match a signed conversion of either DFmode or SFmode to DImode.
1807:
1808: (define_insn ""
1809: [(set (match_operand:DI 0 "general_operand" "=rm")
1810: (fix:DI (fix:XF (match_operand:XF 1 "register_operand" "f"))))
1811: (clobber (match_dup 1))
1812: (clobber (match_operand:SI 2 "memory_operand" "m"))
1813: (clobber (match_operand:SI 3 "memory_operand" "m"))
1814: (clobber (match_scratch:SI 4 "=&q"))]
1815: "TARGET_80387"
1816: "* return (char *) output_fix_trunc (insn, operands);")
1817:
1818: (define_insn ""
1819: [(set (match_operand:DI 0 "general_operand" "=rm")
1820: (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f"))))
1821: (clobber (match_dup 1))
1822: (clobber (match_operand:SI 2 "memory_operand" "m"))
1823: (clobber (match_operand:SI 3 "memory_operand" "m"))
1824: (clobber (match_scratch:SI 4 "=&q"))]
1825: "TARGET_80387"
1826: "* return (char *) output_fix_trunc (insn, operands);")
1827:
1828: (define_insn ""
1829: [(set (match_operand:DI 0 "general_operand" "=rm")
1830: (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f"))))
1831: (clobber (match_dup 1))
1832: (clobber (match_operand:SI 2 "memory_operand" "m"))
1833: (clobber (match_operand:SI 3 "memory_operand" "m"))
1834: (clobber (match_scratch:SI 4 "=&q"))]
1835: "TARGET_80387"
1836: "* return (char *) output_fix_trunc (insn, operands);")
1837:
1838: ;; Signed MODE_FLOAT conversion to SImode.
1839:
1840: (define_expand "fix_truncxfsi2"
1841: [(parallel [(set (match_operand:SI 0 "general_operand" "")
1842: (fix:SI
1843: (fix:XF (match_operand:XF 1 "register_operand" ""))))
1844: (clobber (match_dup 2))
1845: (clobber (match_dup 3))
1846: (clobber (match_scratch:SI 4 ""))])]
1847: "TARGET_80387"
1848: "
1849: {
1850: operands[2] = (rtx) assign_386_stack_local (SImode, 0);
1851: operands[3] = (rtx) assign_386_stack_local (SImode, 1);
1852: }")
1853:
1854: (define_expand "fix_truncdfsi2"
1855: [(parallel [(set (match_operand:SI 0 "general_operand" "")
1856: (fix:SI
1857: (fix:DF (match_operand:DF 1 "register_operand" ""))))
1858: (clobber (match_dup 2))
1859: (clobber (match_dup 3))
1860: (clobber (match_scratch:SI 4 ""))])]
1861: "TARGET_80387"
1862: "
1863: {
1864: operands[2] = (rtx) assign_386_stack_local (SImode, 0);
1865: operands[3] = (rtx) assign_386_stack_local (SImode, 1);
1866: }")
1867:
1868: (define_expand "fix_truncsfsi2"
1869: [(parallel [(set (match_operand:SI 0 "general_operand" "")
1870: (fix:SI
1871: (fix:SF (match_operand:SF 1 "register_operand" ""))))
1872: (clobber (match_dup 2))
1873: (clobber (match_dup 3))
1874: (clobber (match_scratch:SI 4 ""))])]
1875: "TARGET_80387"
1876: "
1877: {
1878: operands[2] = (rtx) assign_386_stack_local (SImode, 0);
1879: operands[3] = (rtx) assign_386_stack_local (SImode, 1);
1880: }")
1881:
1882: (define_insn ""
1883: [(set (match_operand:SI 0 "general_operand" "=rm")
1884: (fix:SI (fix:XF (match_operand:XF 1 "register_operand" "f"))))
1885: (clobber (match_operand:SI 2 "memory_operand" "m"))
1886: (clobber (match_operand:SI 3 "memory_operand" "m"))
1887: (clobber (match_scratch:SI 4 "=&q"))]
1888: "TARGET_80387"
1889: "* return (char *) output_fix_trunc (insn, operands);")
1890:
1891: (define_insn ""
1892: [(set (match_operand:SI 0 "general_operand" "=rm")
1893: (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))
1894: (clobber (match_operand:SI 2 "memory_operand" "m"))
1895: (clobber (match_operand:SI 3 "memory_operand" "m"))
1896: (clobber (match_scratch:SI 4 "=&q"))]
1897: "TARGET_80387"
1898: "* return (char *) output_fix_trunc (insn, operands);")
1899:
1900: (define_insn ""
1901: [(set (match_operand:SI 0 "general_operand" "=rm")
1902: (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))
1903: (clobber (match_operand:SI 2 "memory_operand" "m"))
1904: (clobber (match_operand:SI 3 "memory_operand" "m"))
1905: (clobber (match_scratch:SI 4 "=&q"))]
1906: "TARGET_80387"
1907: "* return (char *) output_fix_trunc (insn, operands);")
1908:
1909: ;; Conversion between fixed point and floating point.
1910: ;; The actual pattern that matches these is at the end of this file.
1911:
1912: ;; ??? Possibly represent floatunssidf2 here in gcc2.
1913:
1914: (define_expand "floatsisf2"
1915: [(set (match_operand:SF 0 "register_operand" "")
1916: (float:SF (match_operand:SI 1 "nonimmediate_operand" "")))]
1917: "TARGET_80387"
1918: "")
1919:
1920: (define_expand "floatdisf2"
1921: [(set (match_operand:SF 0 "register_operand" "")
1922: (float:SF (match_operand:DI 1 "nonimmediate_operand" "")))]
1923: "TARGET_80387"
1924: "")
1925:
1926: (define_expand "floatsidf2"
1927: [(set (match_operand:DF 0 "register_operand" "")
1928: (float:DF (match_operand:SI 1 "nonimmediate_operand" "")))]
1929: "TARGET_80387"
1930: "")
1931:
1932: (define_expand "floatdidf2"
1933: [(set (match_operand:DF 0 "register_operand" "")
1934: (float:DF (match_operand:DI 1 "nonimmediate_operand" "")))]
1935: "TARGET_80387"
1936: "")
1937:
1938: (define_expand "floatsixf2"
1939: [(set (match_operand:XF 0 "register_operand" "")
1940: (float:XF (match_operand:SI 1 "nonimmediate_operand" "")))]
1941: "TARGET_80387"
1942: "")
1943:
1944: (define_expand "floatdixf2"
1945: [(set (match_operand:XF 0 "register_operand" "")
1946: (float:XF (match_operand:DI 1 "nonimmediate_operand" "")))]
1947: "TARGET_80387"
1948: "")
1949:
1950: ;; This will convert from SImode or DImode to MODE_FLOAT.
1951:
1952: (define_insn ""
1953: [(set (match_operand:XF 0 "register_operand" "=f")
1954: (float:XF (match_operand:DI 1 "general_operand" "rm")))]
1955: "TARGET_80387"
1956: "*
1957: {
1958: if (NON_STACK_REG_P (operands[1]))
1959: {
1960: output_op_from_reg (operands[1], AS1 (fild%z0,%1));
1961: RET;
1962: }
1963: else if (GET_CODE (operands[1]) == MEM)
1964: return AS1 (fild%z1,%1);
1965: else
1966: abort ();
1967: }")
1968:
1969: (define_insn ""
1970: [(set (match_operand:DF 0 "register_operand" "=f")
1971: (float:DF (match_operand:DI 1 "nonimmediate_operand" "rm")))]
1972: "TARGET_80387"
1973: "*
1974: {
1975: if (NON_STACK_REG_P (operands[1]))
1976: {
1977: output_op_from_reg (operands[1], AS1 (fild%z0,%1));
1978: RET;
1979: }
1980: else if (GET_CODE (operands[1]) == MEM)
1981: return AS1 (fild%z1,%1);
1982: else
1983: abort ();
1984: }")
1985:
1986: (define_insn ""
1987: [(set (match_operand:SF 0 "register_operand" "=f")
1988: (float:SF (match_operand:DI 1 "nonimmediate_operand" "rm")))]
1989: "TARGET_80387"
1990: "*
1991: {
1992: if (NON_STACK_REG_P (operands[1]))
1993: {
1994: output_op_from_reg (operands[1], AS1 (fild%z0,%1));
1995: RET;
1996: }
1997: else if (GET_CODE (operands[1]) == MEM)
1998: return AS1 (fild%z1,%1);
1999: else
2000: abort ();
2001: }")
2002:
2003: (define_insn ""
2004: [(set (match_operand:DF 0 "register_operand" "=f")
2005: (float:DF (match_operand:SI 1 "nonimmediate_operand" "rm")))]
2006: "TARGET_80387"
2007: "*
2008: {
2009: if (NON_STACK_REG_P (operands[1]))
2010: {
2011: output_op_from_reg (operands[1], AS1 (fild%z0,%1));
2012: RET;
2013: }
2014: else if (GET_CODE (operands[1]) == MEM)
2015: return AS1 (fild%z1,%1);
2016: else
2017: abort ();
2018: }")
2019:
2020: (define_insn ""
2021: [(set (match_operand:XF 0 "register_operand" "=f,f")
2022: (float:XF (match_operand:SI 1 "general_operand" "m,!*r")))]
2023: "TARGET_80387"
2024: "*
2025: {
2026: if (NON_STACK_REG_P (operands[1]))
2027: {
2028: output_op_from_reg (operands[1], AS1 (fild%z0,%1));
2029: RET;
2030: }
2031: else if (GET_CODE (operands[1]) == MEM)
2032: return AS1 (fild%z1,%1);
2033: else
2034: abort ();
2035: }")
2036:
2037: (define_insn ""
2038: [(set (match_operand:SF 0 "register_operand" "=f")
2039: (float:SF (match_operand:SI 1 "nonimmediate_operand" "rm")))]
2040: "TARGET_80387"
2041: "*
2042: {
2043: if (NON_STACK_REG_P (operands[1]))
2044: {
2045: output_op_from_reg (operands[1], AS1 (fild%z0,%1));
2046: RET;
2047: }
2048: else if (GET_CODE (operands[1]) == MEM)
2049: return AS1 (fild%z1,%1);
2050: else
2051: abort ();
2052: }")
2053:
2054: ;;- add instructions
2055:
2056: (define_insn "adddi3"
2057: [(set (match_operand:DI 0 "general_operand" "=&r,ro")
2058: (plus:DI (match_operand:DI 1 "general_operand" "%0,0")
2059: (match_operand:DI 2 "general_operand" "o,riF")))]
2060: ""
2061: "*
2062: {
2063: rtx low[3], high[3];
2064:
2065: CC_STATUS_INIT;
2066:
2067: split_di (operands, 3, low, high);
2068:
2069: if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
2070: {
2071: output_asm_insn (AS2 (add%L0,%2,%0), low);
2072: output_asm_insn (AS2 (adc%L0,%2,%0), high);
2073: }
2074: else
2075: output_asm_insn (AS2 (add%L0,%2,%0), high);
2076: RET;
2077: }")
2078:
2079: ;; On a 486, it is faster to do movl/addl than to do a single leal if
2080: ;; operands[1] and operands[2] are both registers.
2081:
2082: (define_insn "addsi3"
2083: [(set (match_operand:SI 0 "general_operand" "=?r,rm,r")
2084: (plus:SI (match_operand:SI 1 "general_operand" "%r,0,0")
2085: (match_operand:SI 2 "general_operand" "ri,ri,rm")))]
2086: ""
2087: "*
2088: {
2089: if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1]))
2090: {
2091: if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
2092: return AS2 (add%L0,%1,%0);
2093:
2094: if (! TARGET_486 || ! REG_P (operands[2]))
2095: {
2096: CC_STATUS_INIT;
2097:
2098: if (operands[2] == stack_pointer_rtx)
2099: {
2100: rtx temp;
2101:
2102: temp = operands[1];
2103: operands[1] = operands[2];
2104: operands[2] = temp;
2105: }
2106: if (operands[2] != stack_pointer_rtx)
2107: {
2108: operands[1] = SET_SRC (PATTERN (insn));
2109: return AS2 (lea%L0,%a1,%0);
2110: }
2111: }
2112:
2113: output_asm_insn (AS2 (mov%L0,%1,%0), operands);
2114: }
2115:
2116: if (operands[2] == const1_rtx)
2117: return AS1 (inc%L0,%0);
2118:
2119: if (operands[2] == constm1_rtx)
2120: return AS1 (dec%L0,%0);
2121:
2122: return AS2 (add%L0,%2,%0);
2123: }")
2124:
2125: ;; ??? `lea' here, for three operand add? If leaw is used, only %bx,
2126: ;; %si and %di can appear in SET_SRC, and output_asm_insn might not be
2127: ;; able to handle the operand. But leal always works?
2128:
2129: (define_insn "addhi3"
2130: [(set (match_operand:HI 0 "general_operand" "=rm,r")
2131: (plus:HI (match_operand:HI 1 "general_operand" "%0,0")
2132: (match_operand:HI 2 "general_operand" "ri,rm")))]
2133: ""
2134: "*
2135: {
2136: /* ??? what about offsettable memory references? */
2137: if (QI_REG_P (operands[0])
2138: && GET_CODE (operands[2]) == CONST_INT
2139: && (INTVAL (operands[2]) & 0xff) == 0)
2140: {
2141: CC_STATUS_INIT;
2142:
2143: operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
2144:
2145: if (operands[2] == const1_rtx)
2146: return AS1 (inc%B0,%h0);
2147:
2148: if (operands[2] == constm1_rtx)
2149: return AS1 (dec%B0,%h0);
2150:
2151: return AS2 (add%B0,%2,%h0);
2152: }
2153:
2154: if (operands[2] == const1_rtx)
2155: return AS1 (inc%W0,%0);
2156:
2157: if (operands[2] == constm1_rtx)
2158: return AS1 (dec%W0,%0);
2159:
2160: return AS2 (add%W0,%2,%0);
2161: }")
2162:
2163: (define_insn "addqi3"
2164: [(set (match_operand:QI 0 "general_operand" "=qm,q")
2165: (plus:QI (match_operand:QI 1 "general_operand" "%0,0")
2166: (match_operand:QI 2 "general_operand" "qn,qmn")))]
2167: ""
2168: "*
2169: {
2170: if (operands[2] == const1_rtx)
2171: return AS1 (inc%B0,%0);
2172:
2173: if (operands[2] == constm1_rtx)
2174: return AS1 (dec%B0,%0);
2175:
2176: return AS2 (add%B0,%2,%0);
2177: }")
2178:
2179: ;Lennart Augustsson <[email protected]>
2180: ;says this pattern just makes slower code:
2181: ; pushl %ebp
2182: ; addl $-80,(%esp)
2183: ;instead of
2184: ; leal -80(%ebp),%eax
2185: ; pushl %eax
2186: ;
2187: ;(define_insn ""
2188: ; [(set (match_operand:SI 0 "push_operand" "=<")
2189: ; (plus:SI (match_operand:SI 1 "general_operand" "%r")
2190: ; (match_operand:SI 2 "general_operand" "ri")))]
2191: ; ""
2192: ; "*
2193: ;{
2194: ; rtx xops[4];
2195: ; xops[0] = operands[0];
2196: ; xops[1] = operands[1];
2197: ; xops[2] = operands[2];
2198: ; xops[3] = gen_rtx (MEM, SImode, stack_pointer_rtx);
2199: ; output_asm_insn (\"push%z1 %1\", xops);
2200: ; output_asm_insn (AS2 (add%z3,%2,%3), xops);
2201: ; RET;
2202: ;}")
2203:
2204: ;; addsi3 is faster, so put this after.
2205:
2206: (define_insn ""
2207: [(set (match_operand:SI 0 "register_operand" "=r")
2208: (match_operand:QI 1 "address_operand" "p"))]
2209: ""
2210: "*
2211: {
2212: CC_STATUS_INIT;
2213: /* Adding a constant to a register is faster with an add. */
2214: /* ??? can this ever happen? */
2215: if (GET_CODE (operands[1]) == PLUS
2216: && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
2217: && rtx_equal_p (operands[0], XEXP (operands[1], 0)))
2218: {
2219: operands[1] = XEXP (operands[1], 1);
2220:
2221: if (operands[1] == const1_rtx)
2222: return AS1 (inc%L0,%0);
2223:
2224: if (operands[1] == constm1_rtx)
2225: return AS1 (dec%L0,%0);
2226:
2227: return AS2 (add%L0,%1,%0);
2228: }
2229: return AS2 (lea%L0,%a1,%0);
2230: }")
2231:
2232: ;; The patterns that match these are at the end of this file.
2233:
2234: (define_expand "addxf3"
2235: [(set (match_operand:XF 0 "register_operand" "")
2236: (plus:XF (match_operand:XF 1 "nonimmediate_operand" "")
2237: (match_operand:XF 2 "nonimmediate_operand" "")))]
2238: "TARGET_80387"
2239: "")
2240:
2241: (define_expand "adddf3"
2242: [(set (match_operand:DF 0 "register_operand" "")
2243: (plus:DF (match_operand:DF 1 "nonimmediate_operand" "")
2244: (match_operand:DF 2 "nonimmediate_operand" "")))]
2245: "TARGET_80387"
2246: "")
2247:
2248: (define_expand "addsf3"
2249: [(set (match_operand:SF 0 "register_operand" "")
2250: (plus:SF (match_operand:SF 1 "nonimmediate_operand" "")
2251: (match_operand:SF 2 "nonimmediate_operand" "")))]
2252: "TARGET_80387"
2253: "")
2254:
2255: ;;- subtract instructions
2256:
2257: (define_insn "subdi3"
2258: [(set (match_operand:DI 0 "general_operand" "=&r,ro")
2259: (minus:DI (match_operand:DI 1 "general_operand" "0,0")
2260: (match_operand:DI 2 "general_operand" "o,riF")))]
2261: ""
2262: "*
2263: {
2264: rtx low[3], high[3];
2265:
2266: CC_STATUS_INIT;
2267:
2268: split_di (operands, 3, low, high);
2269:
2270: if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
2271: {
2272: output_asm_insn (AS2 (sub%L0,%2,%0), low);
2273: output_asm_insn (AS2 (sbb%L0,%2,%0), high);
2274: }
2275: else
2276: output_asm_insn (AS2 (sub%L0,%2,%0), high);
2277:
2278: RET;
2279: }")
2280:
2281: (define_insn "subsi3"
2282: [(set (match_operand:SI 0 "general_operand" "=rm,r")
2283: (minus:SI (match_operand:SI 1 "general_operand" "0,0")
2284: (match_operand:SI 2 "general_operand" "ri,rm")))]
2285: ""
2286: "* return AS2 (sub%L0,%2,%0);")
2287:
2288: (define_insn "subhi3"
2289: [(set (match_operand:HI 0 "general_operand" "=rm,r")
2290: (minus:HI (match_operand:HI 1 "general_operand" "0,0")
2291: (match_operand:HI 2 "general_operand" "ri,rm")))]
2292: ""
2293: "* return AS2 (sub%W0,%2,%0);")
2294:
2295: (define_insn "subqi3"
2296: [(set (match_operand:QI 0 "general_operand" "=qm,q")
2297: (minus:QI (match_operand:QI 1 "general_operand" "0,0")
2298: (match_operand:QI 2 "general_operand" "qn,qmn")))]
2299: ""
2300: "* return AS2 (sub%B0,%2,%0);")
2301:
2302: ;; The patterns that match these are at the end of this file.
2303:
2304: (define_expand "subxf3"
2305: [(set (match_operand:XF 0 "register_operand" "")
2306: (minus:XF (match_operand:XF 1 "nonimmediate_operand" "")
2307: (match_operand:XF 2 "nonimmediate_operand" "")))]
2308: "TARGET_80387"
2309: "")
2310:
2311: (define_expand "subdf3"
2312: [(set (match_operand:DF 0 "register_operand" "")
2313: (minus:DF (match_operand:DF 1 "nonimmediate_operand" "")
2314: (match_operand:DF 2 "nonimmediate_operand" "")))]
2315: "TARGET_80387"
2316: "")
2317:
2318: (define_expand "subsf3"
2319: [(set (match_operand:SF 0 "register_operand" "")
2320: (minus:SF (match_operand:SF 1 "nonimmediate_operand" "")
2321: (match_operand:SF 2 "nonimmediate_operand" "")))]
2322: "TARGET_80387"
2323: "")
2324:
2325: ;;- multiply instructions
2326:
2327: ;(define_insn "mulqi3"
2328: ; [(set (match_operand:QI 0 "general_operand" "=a")
2329: ; (mult:QI (match_operand:QI 1 "general_operand" "%0")
2330: ; (match_operand:QI 2 "general_operand" "qm")))]
2331: ; ""
2332: ; "imul%B0 %2,%0")
2333:
2334: (define_insn ""
2335: [(set (match_operand:HI 0 "general_operand" "=r")
2336: (mult:SI (match_operand:HI 1 "general_operand" "%0")
2337: (match_operand:HI 2 "general_operand" "r")))]
2338: "GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80"
2339: "* return AS2 (imul%W0,%2,%0);")
2340:
2341: (define_insn "mulhi3"
2342: [(set (match_operand:HI 0 "general_operand" "=r,r")
2343: (mult:SI (match_operand:HI 1 "general_operand" "%0,rm")
2344: (match_operand:HI 2 "general_operand" "g,i")))]
2345: ""
2346: "*
2347: {
2348: if (GET_CODE (operands[1]) == REG
2349: && REGNO (operands[1]) == REGNO (operands[0])
2350: && (GET_CODE (operands[2]) == MEM || GET_CODE (operands[2]) == REG))
2351: /* Assembler has weird restrictions. */
2352: return AS2 (imul%W0,%2,%0);
2353: return AS3 (imul%W0,%2,%1,%0);
2354: }")
2355:
2356: (define_insn ""
2357: [(set (match_operand:SI 0 "general_operand" "=r")
2358: (mult:SI (match_operand:SI 1 "general_operand" "%0")
2359: (match_operand:SI 2 "general_operand" "r")))]
2360: "GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80"
2361: "* return AS2 (imul%L0,%2,%0);")
2362:
2363: (define_insn "mulsi3"
2364: [(set (match_operand:SI 0 "general_operand" "=r,r")
2365: (mult:SI (match_operand:SI 1 "general_operand" "%0,rm")
2366: (match_operand:SI 2 "general_operand" "g,i")))]
2367: ""
2368: "*
2369: {
2370: if (GET_CODE (operands[1]) == REG
2371: && REGNO (operands[1]) == REGNO (operands[0])
2372: && (GET_CODE (operands[2]) == MEM || GET_CODE (operands[2]) == REG))
2373: /* Assembler has weird restrictions. */
2374: return AS2 (imul%L0,%2,%0);
2375: return AS3 (imul%L0,%2,%1,%0);
2376: }")
2377:
2378: (define_insn ""
2379: [(set (match_operand:HI 0 "general_operand" "=a")
2380: (mult:SI (zero_extend:HI
2381: (match_operand:QI 1 "nonimmediate_operand" "%0"))
2382: (zero_extend:HI
2383: (match_operand:QI 2 "nonimmediate_operand" "qm"))))]
2384: ""
2385: "mul%B0 %2")
2386:
2387: ;; The patterns that match these are at the end of this file.
2388:
2389: (define_expand "mulxf3"
2390: [(set (match_operand:XF 0 "register_operand" "")
2391: (mult:XF (match_operand:XF 1 "nonimmediate_operand" "")
2392: (match_operand:XF 2 "nonimmediate_operand" "")))]
2393: "TARGET_80387"
2394: "")
2395:
2396: (define_expand "muldf3"
2397: [(set (match_operand:DF 0 "register_operand" "")
2398: (mult:DF (match_operand:DF 1 "nonimmediate_operand" "")
2399: (match_operand:DF 2 "nonimmediate_operand" "")))]
2400: "TARGET_80387"
2401: "")
2402:
2403: (define_expand "mulsf3"
2404: [(set (match_operand:SF 0 "register_operand" "")
2405: (mult:SF (match_operand:SF 1 "nonimmediate_operand" "")
2406: (match_operand:SF 2 "nonimmediate_operand" "")))]
2407: "TARGET_80387"
2408: "")
2409:
2410: ;;- divide instructions
2411:
2412: (define_insn "divqi3"
2413: [(set (match_operand:QI 0 "general_operand" "=a")
2414: (div:QI (match_operand:HI 1 "general_operand" "0")
2415: (match_operand:QI 2 "general_operand" "qm")))]
2416: ""
2417: "idiv%B0 %2")
2418:
2419: (define_insn "udivqi3"
2420: [(set (match_operand:QI 0 "general_operand" "=a")
2421: (udiv:QI (match_operand:HI 1 "general_operand" "0")
2422: (match_operand:QI 2 "general_operand" "qm")))]
2423: ""
2424: "div%B0 %2")
2425:
2426: ;; The patterns that match these are at the end of this file.
2427:
2428: (define_expand "divxf3"
2429: [(set (match_operand:XF 0 "register_operand" "")
2430: (div:XF (match_operand:XF 1 "nonimmediate_operand" "")
2431: (match_operand:XF 2 "nonimmediate_operand" "")))]
2432: "TARGET_80387"
2433: "")
2434:
2435: (define_expand "divdf3"
2436: [(set (match_operand:DF 0 "register_operand" "")
2437: (div:DF (match_operand:DF 1 "nonimmediate_operand" "")
2438: (match_operand:DF 2 "nonimmediate_operand" "")))]
2439: "TARGET_80387"
2440: "")
2441:
2442: (define_expand "divsf3"
2443: [(set (match_operand:SF 0 "register_operand" "")
2444: (div:SF (match_operand:SF 1 "nonimmediate_operand" "")
2445: (match_operand:SF 2 "nonimmediate_operand" "")))]
2446: "TARGET_80387"
2447: "")
2448:
2449: ;; Remainder instructions.
2450:
2451: (define_insn "divmodsi4"
2452: [(set (match_operand:SI 0 "register_operand" "=a")
2453: (div:SI (match_operand:SI 1 "register_operand" "0")
2454: (match_operand:SI 2 "general_operand" "rm")))
2455: (set (match_operand:SI 3 "register_operand" "=&d")
2456: (mod:SI (match_dup 1) (match_dup 2)))]
2457: ""
2458: "*
2459: {
2460: #ifdef INTEL_SYNTAX
2461: output_asm_insn (\"cdq\", operands);
2462: #else
2463: output_asm_insn (\"cltd\", operands);
2464: #endif
2465: return AS1 (idiv%L0,%2);
2466: }")
2467:
2468: (define_insn "divmodhi4"
2469: [(set (match_operand:HI 0 "register_operand" "=a")
2470: (div:HI (match_operand:HI 1 "register_operand" "0")
2471: (match_operand:HI 2 "general_operand" "rm")))
2472: (set (match_operand:HI 3 "register_operand" "=&d")
2473: (mod:HI (match_dup 1) (match_dup 2)))]
2474: ""
2475: "cwtd\;idiv%W0 %2")
2476:
2477: ;; ??? Can we make gcc zero extend operand[0]?
2478: (define_insn "udivmodsi4"
2479: [(set (match_operand:SI 0 "register_operand" "=a")
2480: (udiv:SI (match_operand:SI 1 "register_operand" "0")
2481: (match_operand:SI 2 "general_operand" "rm")))
2482: (set (match_operand:SI 3 "register_operand" "=&d")
2483: (umod:SI (match_dup 1) (match_dup 2)))]
2484: ""
2485: "*
2486: {
2487: output_asm_insn (AS2 (xor%L3,%3,%3), operands);
2488: return AS1 (div%L0,%2);
2489: }")
2490:
2491: ;; ??? Can we make gcc zero extend operand[0]?
2492: (define_insn "udivmodhi4"
2493: [(set (match_operand:HI 0 "register_operand" "=a")
2494: (udiv:HI (match_operand:HI 1 "register_operand" "0")
2495: (match_operand:HI 2 "general_operand" "rm")))
2496: (set (match_operand:HI 3 "register_operand" "=&d")
2497: (umod:HI (match_dup 1) (match_dup 2)))]
2498: ""
2499: "*
2500: {
2501: output_asm_insn (AS2 (xor%W0,%3,%3), operands);
2502: return AS1 (div%W0,%2);
2503: }")
2504:
2505: /*
2506: ;;this should be a valid double division which we may want to add
2507:
2508: (define_insn ""
2509: [(set (match_operand:SI 0 "register_operand" "=a")
2510: (udiv:DI (match_operand:DI 1 "register_operand" "a")
2511: (match_operand:SI 2 "general_operand" "rm")))
2512: (set (match_operand:SI 3 "register_operand" "=d")
2513: (umod:SI (match_dup 1) (match_dup 2)))]
2514: ""
2515: "div%L0 %2,%0")
2516: */
2517:
2518: ;;- and instructions
2519:
2520: ;; On i386,
2521: ;; movzbl %bl,%ebx
2522: ;; is faster than
2523: ;; andl $255,%ebx
2524: ;;
2525: ;; but if the reg is %eax, then the "andl" is faster.
2526: ;;
2527: ;; On i486, the "andl" is always faster than the "movzbl".
2528: ;;
2529: ;; On both i386 and i486, a three operand AND is as fast with movzbl or
2530: ;; movzwl as with andl, if operands[0] != operands[1].
2531:
2532: ;; The `r' in `rm' for operand 3 looks redundant, but it causes
2533: ;; optional reloads to be generated if op 3 is a pseudo in a stack slot.
2534:
2535: ;; ??? What if we only change one byte of an offsettable memory reference?
2536: (define_insn "andsi3"
2537: [(set (match_operand:SI 0 "general_operand" "=r,r,rm,r")
2538: (and:SI (match_operand:SI 1 "general_operand" "%rm,qm,0,0")
2539: (match_operand:SI 2 "general_operand" "L,K,ri,rm")))]
2540: ""
2541: "*
2542: {
2543: if (GET_CODE (operands[2]) == CONST_INT
2544: && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
2545: {
2546: if (INTVAL (operands[2]) == 0xffff && REG_P (operands[0])
2547: && (! REG_P (operands[1])
2548: || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
2549: && (! TARGET_486 || ! rtx_equal_p (operands[0], operands[1])))
2550: {
2551: /* ??? tege: Should forget CC_STATUS only if we clobber a
2552: remembered operand. Fix that later. */
2553: CC_STATUS_INIT;
2554: #ifdef INTEL_SYNTAX
2555: return AS2 (movzx,%w1,%0);
2556: #else
2557: return AS2 (movz%W0%L0,%w1,%0);
2558: #endif
2559: }
2560:
2561: if (INTVAL (operands[2]) == 0xff && REG_P (operands[0])
2562: && !(REG_P (operands[1]) && NON_QI_REG_P (operands[1]))
2563: && (! REG_P (operands[1])
2564: || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
2565: && (! TARGET_486 || ! rtx_equal_p (operands[0], operands[1])))
2566: {
2567: /* ??? tege: Should forget CC_STATUS only if we clobber a
2568: remembered operand. Fix that later. */
2569: CC_STATUS_INIT;
2570: #ifdef INTEL_SYNTAX
2571: return AS2 (movzx,%b1,%0);
2572: #else
2573: return AS2 (movz%B0%L0,%b1,%0);
2574: #endif
2575: }
2576:
2577: if (QI_REG_P (operands[0]) && ~(INTVAL (operands[2]) | 0xff) == 0)
2578: {
2579: CC_STATUS_INIT;
2580:
2581: if (INTVAL (operands[2]) == 0xffffff00)
2582: {
2583: operands[2] = const0_rtx;
2584: return AS2 (mov%B0,%2,%b0);
2585: }
2586:
2587: operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff);
2588: return AS2 (and%B0,%2,%b0);
2589: }
2590:
2591: if (QI_REG_P (operands[0]) && ~(INTVAL (operands[2]) | 0xff00) == 0)
2592: {
2593: CC_STATUS_INIT;
2594:
2595: if (INTVAL (operands[2]) == 0xffff00ff)
2596: {
2597: operands[2] = const0_rtx;
2598: return AS2 (mov%B0,%2,%h0);
2599: }
2600:
2601: operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
2602: return AS2 (and%B0,%2,%h0);
2603: }
2604:
2605: if (GET_CODE (operands[0]) == MEM && INTVAL (operands[2]) == 0xffff0000)
2606: {
2607: operands[2] = const0_rtx;
2608: return AS2 (mov%W0,%2,%w0);
2609: }
2610: }
2611:
2612: return AS2 (and%L0,%2,%0);
2613: }")
2614:
2615: (define_insn "andhi3"
2616: [(set (match_operand:HI 0 "general_operand" "=rm,r")
2617: (and:HI (match_operand:HI 1 "general_operand" "%0,0")
2618: (match_operand:HI 2 "general_operand" "ri,rm")))]
2619: ""
2620: "*
2621: {
2622: if (GET_CODE (operands[2]) == CONST_INT
2623: && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
2624: {
2625: /* Can we ignore the upper byte? */
2626: if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
2627: && (INTVAL (operands[2]) & 0xff00) == 0xff00)
2628: {
2629: CC_STATUS_INIT;
2630:
2631: if ((INTVAL (operands[2]) & 0xff) == 0)
2632: {
2633: operands[2] = const0_rtx;
2634: return AS2 (mov%B0,%2,%b0);
2635: }
2636:
2637: operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff);
2638: return AS2 (and%B0,%2,%b0);
2639: }
2640:
2641: /* Can we ignore the lower byte? */
2642: /* ??? what about offsettable memory references? */
2643: if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & 0xff) == 0xff)
2644: {
2645: CC_STATUS_INIT;
2646:
2647: if ((INTVAL (operands[2]) & 0xff00) == 0)
2648: {
2649: operands[2] = const0_rtx;
2650: return AS2 (mov%B0,%2,%h0);
2651: }
2652:
2653: operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
2654: return AS2 (and%B0,%2,%h0);
2655: }
2656: }
2657:
2658: return AS2 (and%W0,%2,%0);
2659: }")
2660:
2661: (define_insn "andqi3"
2662: [(set (match_operand:QI 0 "general_operand" "=qm,q")
2663: (and:QI (match_operand:QI 1 "general_operand" "%0,0")
2664: (match_operand:QI 2 "general_operand" "qn,qmn")))]
2665: ""
2666: "* return AS2 (and%B0,%2,%0);")
2667:
2668: /* I am nervous about these two.. add them later..
2669: ;I presume this means that we have something in say op0= eax which is small
2670: ;and we want to and it with memory so we can do this by just an
2671: ;andb m,%al and have success.
2672: (define_insn ""
2673: [(set (match_operand:SI 0 "general_operand" "=r")
2674: (and:SI (zero_extend:SI
2675: (match_operand:HI 1 "nonimmediate_operand" "rm"))
2676: (match_operand:SI 2 "general_operand" "0")))]
2677: "GET_CODE (operands[2]) == CONST_INT
2678: && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))"
2679: "and%W0 %1,%0")
2680:
2681: (define_insn ""
2682: [(set (match_operand:SI 0 "general_operand" "=q")
2683: (and:SI
2684: (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm"))
2685: (match_operand:SI 2 "general_operand" "0")))]
2686: "GET_CODE (operands[2]) == CONST_INT
2687: && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))"
2688: "and%L0 %1,%0")
2689:
2690: */
2691:
2692: ;;- Bit set (inclusive or) instructions
2693:
2694: ;; ??? What if we only change one byte of an offsettable memory reference?
2695: (define_insn "iorsi3"
2696: [(set (match_operand:SI 0 "general_operand" "=rm,r")
2697: (ior:SI (match_operand:SI 1 "general_operand" "%0,0")
2698: (match_operand:SI 2 "general_operand" "ri,rm")))]
2699: ""
2700: "*
2701: {
2702: if (GET_CODE (operands[2]) == CONST_INT
2703: && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
2704: {
2705: if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
2706: && (INTVAL (operands[2]) & ~0xff) == 0)
2707: {
2708: CC_STATUS_INIT;
2709:
2710: if (INTVAL (operands[2]) == 0xff)
2711: return AS2 (mov%B0,%2,%b0);
2712:
2713: return AS2 (or%B0,%2,%b0);
2714: }
2715:
2716: if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff00) == 0)
2717: {
2718: CC_STATUS_INIT;
2719: operands[2] = GEN_INT (INTVAL (operands[2]) >> 8);
2720:
2721: if (INTVAL (operands[2]) == 0xff)
2722: return AS2 (mov%B0,%2,%h0);
2723:
2724: return AS2 (or%B0,%2,%h0);
2725: }
2726: }
2727:
2728: return AS2 (or%L0,%2,%0);
2729: }")
2730:
2731: (define_insn "iorhi3"
2732: [(set (match_operand:HI 0 "general_operand" "=rm,r")
2733: (ior:HI (match_operand:HI 1 "general_operand" "%0,0")
2734: (match_operand:HI 2 "general_operand" "ri,rm")))]
2735: ""
2736: "*
2737: {
2738: if (GET_CODE (operands[2]) == CONST_INT
2739: && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
2740: {
2741: /* Can we ignore the upper byte? */
2742: if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
2743: && (INTVAL (operands[2]) & 0xff00) == 0)
2744: {
2745: CC_STATUS_INIT;
2746: if (INTVAL (operands[2]) & 0xffff0000)
2747: operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff);
2748:
2749: if (INTVAL (operands[2]) == 0xff)
2750: return AS2 (mov%B0,%2,%b0);
2751:
2752: return AS2 (or%B0,%2,%b0);
2753: }
2754:
2755: /* Can we ignore the lower byte? */
2756: /* ??? what about offsettable memory references? */
2757: if (QI_REG_P (operands[0])
2758: && (INTVAL (operands[2]) & 0xff) == 0)
2759: {
2760: CC_STATUS_INIT;
2761: operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
2762:
2763: if (INTVAL (operands[2]) == 0xff)
2764: return AS2 (mov%B0,%2,%h0);
2765:
2766: return AS2 (or%B0,%2,%h0);
2767: }
2768: }
2769:
2770: return AS2 (or%W0,%2,%0);
2771: }")
2772:
2773: (define_insn "iorqi3"
2774: [(set (match_operand:QI 0 "general_operand" "=qm,q")
2775: (ior:QI (match_operand:QI 1 "general_operand" "%0,0")
2776: (match_operand:QI 2 "general_operand" "qn,qmn")))]
2777: ""
2778: "* return AS2 (or%B0,%2,%0);")
2779:
2780: ;;- xor instructions
2781:
2782: ;; ??? What if we only change one byte of an offsettable memory reference?
2783: (define_insn "xorsi3"
2784: [(set (match_operand:SI 0 "general_operand" "=rm,r")
2785: (xor:SI (match_operand:SI 1 "general_operand" "%0,0")
2786: (match_operand:SI 2 "general_operand" "ri,rm")))]
2787: ""
2788: "*
2789: {
2790: if (GET_CODE (operands[2]) == CONST_INT
2791: && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
2792: {
2793: if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
2794: && (INTVAL (operands[2]) & ~0xff) == 0)
2795: {
2796: CC_STATUS_INIT;
2797:
2798: if (INTVAL (operands[2]) == 0xff)
2799: return AS1 (not%B0,%b0);
2800:
2801: return AS2 (xor%B0,%2,%b0);
2802: }
2803:
2804: if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff00) == 0)
2805: {
2806: CC_STATUS_INIT;
2807: operands[2] = GEN_INT (INTVAL (operands[2]) >> 8);
2808:
2809: if (INTVAL (operands[2]) == 0xff)
2810: return AS1 (not%B0,%h0);
2811:
2812: return AS2 (xor%B0,%2,%h0);
2813: }
2814: }
2815:
2816: return AS2 (xor%L0,%2,%0);
2817: }")
2818:
2819: (define_insn "xorhi3"
2820: [(set (match_operand:HI 0 "general_operand" "=rm,r")
2821: (xor:HI (match_operand:HI 1 "general_operand" "%0,0")
2822: (match_operand:HI 2 "general_operand" "ri,rm")))]
2823: ""
2824: "*
2825: {
2826: if (GET_CODE (operands[2]) == CONST_INT
2827: && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
2828: {
2829: /* Can we ignore the upper byte? */
2830: if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
2831: && (INTVAL (operands[2]) & 0xff00) == 0)
2832: {
2833: CC_STATUS_INIT;
2834: if (INTVAL (operands[2]) & 0xffff0000)
2835: operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff);
2836:
2837: if (INTVAL (operands[2]) == 0xff)
2838: return AS1 (not%B0,%b0);
2839:
2840: return AS2 (xor%B0,%2,%b0);
2841: }
2842:
2843: /* Can we ignore the lower byte? */
2844: /* ??? what about offsettable memory references? */
2845: if (QI_REG_P (operands[0])
2846: && (INTVAL (operands[2]) & 0xff) == 0)
2847: {
2848: CC_STATUS_INIT;
2849: operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
2850:
2851: if (INTVAL (operands[2]) == 0xff)
2852: return AS1 (not%B0,%h0);
2853:
2854: return AS2 (xor%B0,%2,%h0);
2855: }
2856: }
2857:
2858: return AS2 (xor%W0,%2,%0);
2859: }")
2860:
2861: (define_insn "xorqi3"
2862: [(set (match_operand:QI 0 "general_operand" "=qm,q")
2863: (xor:QI (match_operand:QI 1 "general_operand" "%0,0")
2864: (match_operand:QI 2 "general_operand" "qn,qm")))]
2865: ""
2866: "* return AS2 (xor%B0,%2,%0);")
2867:
2868: ;;- negation instructions
2869:
2870: (define_insn "negdi2"
2871: [(set (match_operand:DI 0 "general_operand" "=&ro")
2872: (neg:DI (match_operand:DI 1 "general_operand" "0")))]
2873: ""
2874: "*
2875: {
2876: rtx xops[2], low[1], high[1];
2877:
2878: CC_STATUS_INIT;
2879:
2880: split_di (operands, 1, low, high);
2881: xops[0] = const0_rtx;
2882: xops[1] = high[0];
2883:
2884: output_asm_insn (AS1 (neg%L0,%0), low);
2885: output_asm_insn (AS2 (adc%L1,%0,%1), xops);
2886: output_asm_insn (AS1 (neg%L0,%0), high);
2887: RET;
2888: }")
2889:
2890: (define_insn "negsi2"
2891: [(set (match_operand:SI 0 "general_operand" "=rm")
2892: (neg:SI (match_operand:SI 1 "general_operand" "0")))]
2893: ""
2894: "neg%L0 %0")
2895:
2896: (define_insn "neghi2"
2897: [(set (match_operand:HI 0 "general_operand" "=rm")
2898: (neg:HI (match_operand:HI 1 "general_operand" "0")))]
2899: ""
2900: "neg%W0 %0")
2901:
2902: (define_insn "negqi2"
2903: [(set (match_operand:QI 0 "general_operand" "=qm")
2904: (neg:QI (match_operand:QI 1 "general_operand" "0")))]
2905: ""
2906: "neg%B0 %0")
2907:
2908: (define_insn "negsf2"
2909: [(set (match_operand:SF 0 "register_operand" "=f")
2910: (neg:SF (match_operand:SF 1 "general_operand" "0")))]
2911: "TARGET_80387"
2912: "fchs")
2913:
2914: (define_insn "negdf2"
2915: [(set (match_operand:DF 0 "register_operand" "=f")
2916: (neg:DF (match_operand:DF 1 "general_operand" "0")))]
2917: "TARGET_80387"
2918: "fchs")
2919:
2920: (define_insn ""
2921: [(set (match_operand:DF 0 "register_operand" "=f")
2922: (neg:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))]
2923: "TARGET_80387"
2924: "fchs")
2925:
2926: (define_insn "negxf2"
2927: [(set (match_operand:XF 0 "register_operand" "=f")
2928: (neg:XF (match_operand:XF 1 "general_operand" "0")))]
2929: "TARGET_80387"
2930: "fchs")
2931:
2932: (define_insn ""
2933: [(set (match_operand:XF 0 "register_operand" "=f")
2934: (neg:XF (float_extend:XF (match_operand:DF 1 "general_operand" "0"))))]
2935: "TARGET_80387"
2936: "fchs")
2937:
2938: ;; Absolute value instructions
2939:
2940: (define_insn "abssf2"
2941: [(set (match_operand:SF 0 "register_operand" "=f")
2942: (abs:SF (match_operand:SF 1 "general_operand" "0")))]
2943: "TARGET_80387"
2944: "fabs")
2945:
2946: (define_insn "absdf2"
2947: [(set (match_operand:DF 0 "register_operand" "=f")
2948: (abs:DF (match_operand:DF 1 "general_operand" "0")))]
2949: "TARGET_80387"
2950: "fabs")
2951:
2952: (define_insn ""
2953: [(set (match_operand:DF 0 "register_operand" "=f")
2954: (abs:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))]
2955: "TARGET_80387"
2956: "fabs")
2957:
2958: (define_insn "absxf2"
2959: [(set (match_operand:XF 0 "register_operand" "=f")
2960: (abs:XF (match_operand:XF 1 "general_operand" "0")))]
2961: "TARGET_80387"
2962: "fabs")
2963:
2964: (define_insn ""
2965: [(set (match_operand:XF 0 "register_operand" "=f")
2966: (abs:XF (float_extend:XF (match_operand:DF 1 "general_operand" "0"))))]
2967: "TARGET_80387"
2968: "fabs")
2969:
2970: (define_insn "sqrtsf2"
2971: [(set (match_operand:SF 0 "register_operand" "=f")
2972: (sqrt:SF (match_operand:SF 1 "general_operand" "0")))]
2973: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
2974: "fsqrt")
2975:
2976: (define_insn "sqrtdf2"
2977: [(set (match_operand:DF 0 "register_operand" "=f")
2978: (sqrt:DF (match_operand:DF 1 "general_operand" "0")))]
2979: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
2980: "fsqrt")
2981:
2982: (define_insn ""
2983: [(set (match_operand:DF 0 "register_operand" "=f")
2984: (sqrt:DF (float_extend:DF
2985: (match_operand:SF 1 "general_operand" "0"))))]
2986: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
2987: "fsqrt")
2988:
2989: (define_insn "sqrtxf2"
2990: [(set (match_operand:XF 0 "register_operand" "=f")
2991: (sqrt:XF (match_operand:XF 1 "general_operand" "0")))]
2992: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
2993: "fsqrt")
2994:
2995: (define_insn ""
2996: [(set (match_operand:XF 0 "register_operand" "=f")
2997: (sqrt:XF (float_extend:XF
2998: (match_operand:DF 1 "general_operand" "0"))))]
2999: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
3000: "fsqrt")
3001:
3002: (define_insn ""
3003: [(set (match_operand:XF 0 "register_operand" "=f")
3004: (sqrt:XF (float_extend:XF
3005: (match_operand:SF 1 "general_operand" "0"))))]
3006: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
3007: "fsqrt")
3008:
3009: (define_insn "sindf2"
3010: [(set (match_operand:DF 0 "register_operand" "=f")
3011: (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))]
3012: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
3013: "fsin")
3014:
3015: (define_insn "sinsf2"
3016: [(set (match_operand:SF 0 "register_operand" "=f")
3017: (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))]
3018: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
3019: "fsin")
3020:
3021: (define_insn ""
3022: [(set (match_operand:DF 0 "register_operand" "=f")
3023: (unspec:DF [(float_extend:DF
3024: (match_operand:SF 1 "register_operand" "0"))] 1))]
3025: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
3026: "fsin")
3027:
3028: (define_insn "cosdf2"
3029: [(set (match_operand:DF 0 "register_operand" "=f")
3030: (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))]
3031: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
3032: "fcos")
3033:
3034: (define_insn "cossf2"
3035: [(set (match_operand:SF 0 "register_operand" "=f")
3036: (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))]
3037: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
3038: "fcos")
3039:
3040: (define_insn ""
3041: [(set (match_operand:DF 0 "register_operand" "=f")
3042: (unspec:DF [(float_extend:DF
3043: (match_operand:SF 1 "register_operand" "0"))] 2))]
3044: "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)"
3045: "fcos")
3046:
3047: ;;- one complement instructions
3048:
3049: (define_insn "one_cmplsi2"
3050: [(set (match_operand:SI 0 "general_operand" "=rm")
3051: (not:SI (match_operand:SI 1 "general_operand" "0")))]
3052: ""
3053: "not%L0 %0")
3054:
3055: (define_insn "one_cmplhi2"
3056: [(set (match_operand:HI 0 "general_operand" "=rm")
3057: (not:HI (match_operand:HI 1 "general_operand" "0")))]
3058: ""
3059: "not%W0 %0")
3060:
3061: (define_insn "one_cmplqi2"
3062: [(set (match_operand:QI 0 "general_operand" "=qm")
3063: (not:QI (match_operand:QI 1 "general_operand" "0")))]
3064: ""
3065: "not%B0 %0")
3066:
3067: ;;- arithmetic shift instructions
3068:
3069: ;; DImode shifts are implemented using the i386 "shift double" opcode,
3070: ;; which is written as "sh[lr]d[lw] imm,reg,reg/mem". If the shift count
3071: ;; is variable, then the count is in %cl and the "imm" operand is dropped
3072: ;; from the assembler input.
3073:
3074: ;; This instruction shifts the target reg/mem as usual, but instead of
3075: ;; shifting in zeros, bits are shifted in from reg operand. If the insn
3076: ;; is a left shift double, bits are taken from the high order bits of
3077: ;; reg, else if the insn is a shift right double, bits are taken from the
3078: ;; low order bits of reg. So if %eax is "1234" and %edx is "5678",
3079: ;; "shldl $8,%edx,%eax" leaves %edx unchanged and sets %eax to "2345".
3080:
3081: ;; Since sh[lr]d does not change the `reg' operand, that is done
3082: ;; separately, making all shifts emit pairs of shift double and normal
3083: ;; shift. Since sh[lr]d does not shift more than 31 bits, and we wish to
3084: ;; support a 63 bit shift, each shift where the count is in a reg expands
3085: ;; to three pairs. If the overall shift is by N bits, then the first two
3086: ;; pairs shift by N / 2 and the last pair by N & 1.
3087:
3088: ;; If the shift count is a constant, we need never emit more than one
3089: ;; shift pair, instead using moves and sign extension for counts greater
3090: ;; than 31.
3091:
3092: (define_expand "ashldi3"
3093: [(set (match_operand:DI 0 "register_operand" "")
3094: (ashift:DI (match_operand:DI 1 "register_operand" "")
3095: (match_operand:QI 2 "nonmemory_operand" "")))]
3096: ""
3097: "
3098: {
3099: if (GET_CODE (operands[2]) != CONST_INT
3100: || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J'))
3101: {
3102: operands[2] = copy_to_mode_reg (QImode, operands[2]);
3103: emit_insn (gen_ashldi3_non_const_int (operands[0], operands[1],
3104: operands[2]));
3105: }
3106: else
3107: emit_insn (gen_ashldi3_const_int (operands[0], operands[1], operands[2]));
3108:
3109: DONE;
3110: }")
3111:
3112: (define_insn "ashldi3_const_int"
3113: [(set (match_operand:DI 0 "register_operand" "=&r")
3114: (ashift:DI (match_operand:DI 1 "register_operand" "0")
3115: (match_operand:QI 2 "const_int_operand" "J")))]
3116: ""
3117: "*
3118: {
3119: rtx xops[4], low[1], high[1];
3120:
3121: CC_STATUS_INIT;
3122:
3123: split_di (operands, 1, low, high);
3124: xops[0] = operands[2];
3125: xops[1] = const1_rtx;
3126: xops[2] = low[0];
3127: xops[3] = high[0];
3128:
3129: if (INTVAL (xops[0]) > 31)
3130: {
3131: output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */
3132: output_asm_insn (AS2 (xor%L2,%2,%2), xops);
3133:
3134: if (INTVAL (xops[0]) > 32)
3135: {
3136: xops[0] = GEN_INT (INTVAL (xops[0]) - 32);
3137: output_asm_insn (AS2 (sal%L3,%0,%3), xops); /* Remaining shift */
3138: }
3139: }
3140: else
3141: {
3142: output_asm_insn (AS3 (shld%L3,%0,%2,%3), xops);
3143: output_asm_insn (AS2 (sal%L2,%0,%2), xops);
3144: }
3145: RET;
3146: }")
3147:
3148: (define_insn "ashldi3_non_const_int"
3149: [(set (match_operand:DI 0 "register_operand" "=&r")
3150: (ashift:DI (match_operand:DI 1 "register_operand" "0")
3151: (match_operand:QI 2 "register_operand" "c")))
3152: (clobber (match_dup 2))]
3153: ""
3154: "*
3155: {
3156: rtx xops[4], low[1], high[1];
3157:
3158: CC_STATUS_INIT;
3159:
3160: split_di (operands, 1, low, high);
3161: xops[0] = operands[2];
3162: xops[1] = const1_rtx;
3163: xops[2] = low[0];
3164: xops[3] = high[0];
3165:
3166: output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */
3167:
3168: output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops);
3169: output_asm_insn (AS2 (sal%L2,%0,%2), xops);
3170: output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops);
3171: output_asm_insn (AS2 (sal%L2,%0,%2), xops);
3172:
3173: xops[1] = GEN_INT (7); /* shift count & 1 */
3174:
3175: output_asm_insn (AS2 (shr%B0,%1,%0), xops);
3176:
3177: output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops);
3178: output_asm_insn (AS2 (sal%L2,%0,%2), xops);
3179:
3180: RET;
3181: }")
3182:
3183: ;; On i386 and i486, "addl reg,reg" is faster than "sall $1,reg"
3184: ;; On i486, movl/sall appears slightly faster than leal, but the leal
3185: ;; is smaller - use leal for now unless the shift count is 1.
3186:
3187: (define_insn "ashlsi3"
3188: [(set (match_operand:SI 0 "general_operand" "=r,rm")
3189: (ashift:SI (match_operand:SI 1 "general_operand" "r,0")
3190: (match_operand:SI 2 "nonmemory_operand" "M,cI")))]
3191: ""
3192: "*
3193: {
3194: if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1]))
3195: {
3196: if (TARGET_486 && INTVAL (operands[2]) == 1)
3197: {
3198: output_asm_insn (AS2 (mov%L0,%1,%0), operands);
3199: return AS2 (add%L0,%1,%0);
3200: }
3201: else
3202: {
3203: CC_STATUS_INIT;
3204:
3205: if (operands[1] == stack_pointer_rtx)
3206: {
3207: output_asm_insn (AS2 (mov%L0,%1,%0), operands);
3208: operands[1] = operands[0];
3209: }
3210: operands[1] = gen_rtx (MULT, SImode, operands[1],
3211: GEN_INT (1 << INTVAL (operands[2])));
3212: return AS2 (lea%L0,%a1,%0);
3213: }
3214: }
3215:
3216: if (REG_P (operands[2]))
3217: return AS2 (sal%L0,%b2,%0);
3218:
3219: if (REG_P (operands[0]) && operands[2] == const1_rtx)
3220: return AS2 (add%L0,%0,%0);
3221:
3222: return AS2 (sal%L0,%2,%0);
3223: }")
3224:
3225: (define_insn "ashlhi3"
3226: [(set (match_operand:HI 0 "general_operand" "=rm")
3227: (ashift:HI (match_operand:HI 1 "general_operand" "0")
3228: (match_operand:HI 2 "nonmemory_operand" "cI")))]
3229: ""
3230: "*
3231: {
3232: if (REG_P (operands[2]))
3233: return AS2 (sal%W0,%b2,%0);
3234:
3235: if (REG_P (operands[0]) && operands[2] == const1_rtx)
3236: return AS2 (add%W0,%0,%0);
3237:
3238: return AS2 (sal%W0,%2,%0);
3239: }")
3240:
3241: (define_insn "ashlqi3"
3242: [(set (match_operand:QI 0 "general_operand" "=qm")
3243: (ashift:QI (match_operand:QI 1 "general_operand" "0")
3244: (match_operand:QI 2 "nonmemory_operand" "cI")))]
3245: ""
3246: "*
3247: {
3248: if (REG_P (operands[2]))
3249: return AS2 (sal%B0,%b2,%0);
3250:
3251: if (REG_P (operands[0]) && operands[2] == const1_rtx)
3252: return AS2 (add%B0,%0,%0);
3253:
3254: return AS2 (sal%B0,%2,%0);
3255: }")
3256:
3257: ;; See comment above `ashldi3' about how this works.
3258:
3259: (define_expand "ashrdi3"
3260: [(set (match_operand:DI 0 "register_operand" "")
3261: (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
3262: (match_operand:QI 2 "nonmemory_operand" "")))]
3263: ""
3264: "
3265: {
3266: if (GET_CODE (operands[2]) != CONST_INT
3267: || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J'))
3268: {
3269: operands[2] = copy_to_mode_reg (QImode, operands[2]);
3270: emit_insn (gen_ashrdi3_non_const_int (operands[0], operands[1],
3271: operands[2]));
3272: }
3273: else
3274: emit_insn (gen_ashrdi3_const_int (operands[0], operands[1], operands[2]));
3275:
3276: DONE;
3277: }")
3278:
3279: (define_insn "ashrdi3_const_int"
3280: [(set (match_operand:DI 0 "register_operand" "=&r")
3281: (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
3282: (match_operand:QI 2 "const_int_operand" "J")))]
3283: ""
3284: "*
3285: {
3286: rtx xops[4], low[1], high[1];
3287:
3288: CC_STATUS_INIT;
3289:
3290: split_di (operands, 1, low, high);
3291: xops[0] = operands[2];
3292: xops[1] = const1_rtx;
3293: xops[2] = low[0];
3294: xops[3] = high[0];
3295:
3296: if (INTVAL (xops[0]) > 31)
3297: {
3298: xops[1] = GEN_INT (31);
3299: output_asm_insn (AS2 (mov%L2,%3,%2), xops);
3300: output_asm_insn (AS2 (sar%L3,%1,%3), xops); /* shift by 32 */
3301:
3302: if (INTVAL (xops[0]) > 32)
3303: {
3304: xops[0] = GEN_INT (INTVAL (xops[0]) - 32);
3305: output_asm_insn (AS2 (sar%L2,%0,%2), xops); /* Remaining shift */
3306: }
3307: }
3308: else
3309: {
3310: output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops);
3311: output_asm_insn (AS2 (sar%L3,%0,%3), xops);
3312: }
3313:
3314: RET;
3315: }")
3316:
3317: (define_insn "ashrdi3_non_const_int"
3318: [(set (match_operand:DI 0 "register_operand" "=&r")
3319: (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
3320: (match_operand:QI 2 "register_operand" "c")))
3321: (clobber (match_dup 2))]
3322: ""
3323: "*
3324: {
3325: rtx xops[4], low[1], high[1];
3326:
3327: CC_STATUS_INIT;
3328:
3329: split_di (operands, 1, low, high);
3330: xops[0] = operands[2];
3331: xops[1] = const1_rtx;
3332: xops[2] = low[0];
3333: xops[3] = high[0];
3334:
3335: output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */
3336:
3337: output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
3338: output_asm_insn (AS2 (sar%L3,%0,%3), xops);
3339: output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
3340: output_asm_insn (AS2 (sar%L3,%0,%3), xops);
3341:
3342: xops[1] = GEN_INT (7); /* shift count & 1 */
3343:
3344: output_asm_insn (AS2 (shr%B0,%1,%0), xops);
3345:
3346: output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
3347: output_asm_insn (AS2 (sar%L3,%0,%3), xops);
3348:
3349: RET;
3350: }")
3351:
3352: (define_insn "ashrsi3"
3353: [(set (match_operand:SI 0 "general_operand" "=rm")
3354: (ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
3355: (match_operand:SI 2 "nonmemory_operand" "cI")))]
3356: ""
3357: "*
3358: {
3359: if (REG_P (operands[2]))
3360: return AS2 (sar%L0,%b2,%0);
3361: else
3362: return AS2 (sar%L0,%2,%0);
3363: }")
3364:
3365: (define_insn "ashrhi3"
3366: [(set (match_operand:HI 0 "general_operand" "=rm")
3367: (ashiftrt:HI (match_operand:HI 1 "general_operand" "0")
3368: (match_operand:HI 2 "nonmemory_operand" "cI")))]
3369: ""
3370: "*
3371: {
3372: if (REG_P (operands[2]))
3373: return AS2 (sar%W0,%b2,%0);
3374: else
3375: return AS2 (sar%W0,%2,%0);
3376: }")
3377:
3378: (define_insn "ashrqi3"
3379: [(set (match_operand:QI 0 "general_operand" "=qm")
3380: (ashiftrt:QI (match_operand:QI 1 "general_operand" "0")
3381: (match_operand:QI 2 "nonmemory_operand" "cI")))]
3382: ""
3383: "*
3384: {
3385: if (REG_P (operands[2]))
3386: return AS2 (sar%B0,%b2,%0);
3387: else
3388: return AS2 (sar%B0,%2,%0);
3389: }")
3390:
3391: ;;- logical shift instructions
3392:
3393: ;; See comment above `ashldi3' about how this works.
3394:
3395: (define_expand "lshrdi3"
3396: [(set (match_operand:DI 0 "register_operand" "")
3397: (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
3398: (match_operand:QI 2 "nonmemory_operand" "")))]
3399: ""
3400: "
3401: {
3402: if (GET_CODE (operands[2]) != CONST_INT
3403: || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J'))
3404: {
3405: operands[2] = copy_to_mode_reg (QImode, operands[2]);
3406: emit_insn (gen_lshrdi3_non_const_int (operands[0], operands[1],
3407: operands[2]));
3408: }
3409: else
3410: emit_insn (gen_lshrdi3_const_int (operands[0], operands[1], operands[2]));
3411:
3412: DONE;
3413: }")
3414:
3415: (define_insn "lshrdi3_const_int"
3416: [(set (match_operand:DI 0 "register_operand" "=&r")
3417: (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
3418: (match_operand:QI 2 "const_int_operand" "J")))]
3419: ""
3420: "*
3421: {
3422: rtx xops[4], low[1], high[1];
3423:
3424: CC_STATUS_INIT;
3425:
3426: split_di (operands, 1, low, high);
3427: xops[0] = operands[2];
3428: xops[1] = const1_rtx;
3429: xops[2] = low[0];
3430: xops[3] = high[0];
3431:
3432: if (INTVAL (xops[0]) > 31)
3433: {
3434: output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */
3435: output_asm_insn (AS2 (xor%L3,%3,%3), xops);
3436:
3437: if (INTVAL (xops[0]) > 32)
3438: {
3439: xops[0] = GEN_INT (INTVAL (xops[0]) - 32);
3440: output_asm_insn (AS2 (shr%L2,%0,%2), xops); /* Remaining shift */
3441: }
3442: }
3443: else
3444: {
3445: output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops);
3446: output_asm_insn (AS2 (shr%L3,%0,%3), xops);
3447: }
3448:
3449: RET;
3450: }")
3451:
3452: (define_insn "lshrdi3_non_const_int"
3453: [(set (match_operand:DI 0 "register_operand" "=&r")
3454: (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
3455: (match_operand:QI 2 "register_operand" "c")))
3456: (clobber (match_dup 2))]
3457: ""
3458: "*
3459: {
3460: rtx xops[4], low[1], high[1];
3461:
3462: CC_STATUS_INIT;
3463:
3464: split_di (operands, 1, low, high);
3465: xops[0] = operands[2];
3466: xops[1] = const1_rtx;
3467: xops[2] = low[0];
3468: xops[3] = high[0];
3469:
3470: output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */
3471:
3472: output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
3473: output_asm_insn (AS2 (shr%L3,%0,%3), xops);
3474: output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
3475: output_asm_insn (AS2 (shr%L3,%0,%3), xops);
3476:
3477: xops[1] = GEN_INT (7); /* shift count & 1 */
3478:
3479: output_asm_insn (AS2 (shr%B0,%1,%0), xops);
3480:
3481: output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
3482: output_asm_insn (AS2 (shr%L3,%0,%3), xops);
3483:
3484: RET;
3485: }")
3486:
3487: (define_insn "lshrsi3"
3488: [(set (match_operand:SI 0 "general_operand" "=rm")
3489: (lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
3490: (match_operand:SI 2 "nonmemory_operand" "cI")))]
3491: ""
3492: "*
3493: {
3494: if (REG_P (operands[2]))
3495: return AS2 (shr%L0,%b2,%0);
3496: else
3497: return AS2 (shr%L0,%2,%1);
3498: }")
3499:
3500: (define_insn "lshrhi3"
3501: [(set (match_operand:HI 0 "general_operand" "=rm")
3502: (lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
3503: (match_operand:HI 2 "nonmemory_operand" "cI")))]
3504: ""
3505: "*
3506: {
3507: if (REG_P (operands[2]))
3508: return AS2 (shr%W0,%b2,%0);
3509: else
3510: return AS2 (shr%W0,%2,%0);
3511: }")
3512:
3513: (define_insn "lshrqi3"
3514: [(set (match_operand:QI 0 "general_operand" "=qm")
3515: (lshiftrt:QI (match_operand:QI 1 "general_operand" "0")
3516: (match_operand:QI 2 "nonmemory_operand" "cI")))]
3517: ""
3518: "*
3519: {
3520: if (REG_P (operands[2]))
3521: return AS2 (shr%B0,%b2,%0);
3522: else
3523: return AS2 (shr%B0,%2,%0);
3524: }")
3525:
3526: ;;- rotate instructions
3527:
3528: (define_insn "rotlsi3"
3529: [(set (match_operand:SI 0 "general_operand" "=rm")
3530: (rotate:SI (match_operand:SI 1 "general_operand" "0")
3531: (match_operand:SI 2 "nonmemory_operand" "cI")))]
3532: ""
3533: "*
3534: {
3535: if (REG_P (operands[2]))
3536: return AS2 (rol%L0,%b2,%0);
3537: else
3538: return AS2 (rol%L0,%2,%0);
3539: }")
3540:
3541: (define_insn "rotlhi3"
3542: [(set (match_operand:HI 0 "general_operand" "=rm")
3543: (rotate:HI (match_operand:HI 1 "general_operand" "0")
3544: (match_operand:HI 2 "nonmemory_operand" "cI")))]
3545: ""
3546: "*
3547: {
3548: if (REG_P (operands[2]))
3549: return AS2 (rol%W0,%b2,%0);
3550: else
3551: return AS2 (rol%W0,%2,%0);
3552: }")
3553:
3554: (define_insn "rotlqi3"
3555: [(set (match_operand:QI 0 "general_operand" "=qm")
3556: (rotate:QI (match_operand:QI 1 "general_operand" "0")
3557: (match_operand:QI 2 "nonmemory_operand" "cI")))]
3558: ""
3559: "*
3560: {
3561: if (REG_P (operands[2]))
3562: return AS2 (rol%B0,%b2,%0);
3563: else
3564: return AS2 (rol%B0,%2,%0);
3565: }")
3566:
3567: (define_insn "rotrsi3"
3568: [(set (match_operand:SI 0 "general_operand" "=rm")
3569: (rotatert:SI (match_operand:SI 1 "general_operand" "0")
3570: (match_operand:SI 2 "nonmemory_operand" "cI")))]
3571: ""
3572: "*
3573: {
3574: if (REG_P (operands[2]))
3575: return AS2 (ror%L0,%b2,%0);
3576: else
3577: return AS2 (ror%L0,%2,%0);
3578: }")
3579:
3580: (define_insn "rotrhi3"
3581: [(set (match_operand:HI 0 "general_operand" "=rm")
3582: (rotatert:HI (match_operand:HI 1 "general_operand" "0")
3583: (match_operand:HI 2 "nonmemory_operand" "cI")))]
3584: ""
3585: "*
3586: {
3587: if (REG_P (operands[2]))
3588: return AS2 (ror%W0,%b2,%0);
3589: else
3590: return AS2 (ror%W0,%2,%0);
3591: }")
3592:
3593: (define_insn "rotrqi3"
3594: [(set (match_operand:QI 0 "general_operand" "=qm")
3595: (rotatert:QI (match_operand:QI 1 "general_operand" "0")
3596: (match_operand:QI 2 "nonmemory_operand" "cI")))]
3597: ""
3598: "*
3599: {
3600: if (REG_P (operands[2]))
3601: return AS2 (ror%B0,%b2,%0);
3602: else
3603: return AS2 (ror%B0,%2,%0);
3604: }")
3605:
3606: /*
3607: ;; This usually looses. But try a define_expand to recognize a few case
3608: ;; we can do efficiently, such as accessing the "high" QImode registers,
3609: ;; %ah, %bh, %ch, %dh.
3610: (define_insn "insv"
3611: [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+&r")
3612: (match_operand:SI 1 "general_operand" "i")
3613: (match_operand:SI 2 "general_operand" "i"))
3614: (match_operand:SI 3 "general_operand" "ri"))]
3615: ""
3616: "*
3617: {
3618: if (INTVAL (operands[1]) + INTVAL (operands[2]) > GET_MODE_BITSIZE (SImode))
3619: abort ();
3620: if (GET_CODE (operands[3]) == CONST_INT)
3621: {
3622: unsigned int mask = (1 << INTVAL (operands[1])) - 1;
3623: operands[1] = GEN_INT (~(mask << INTVAL (operands[2])));
3624: output_asm_insn (AS2 (and%L0,%1,%0), operands);
3625: operands[3] = GEN_INT (INTVAL (operands[3]) << INTVAL (operands[2]));
3626: output_asm_insn (AS2 (or%L0,%3,%0), operands);
3627: }
3628: else
3629: {
3630: operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]));
3631: if (INTVAL (operands[2]))
3632: output_asm_insn (AS2 (ror%L0,%2,%0), operands);
3633: output_asm_insn (AS3 (shrd%L0,%1,%3,%0), operands);
3634: operands[2] = GEN_INT (BITS_PER_WORD
3635: - INTVAL (operands[1]) - INTVAL (operands[2]));
3636: if (INTVAL (operands[2]))
3637: output_asm_insn (AS2 (ror%L0,%2,%0), operands);
3638: }
3639: RET;
3640: }")
3641: */
3642: /*
3643: ;; ??? There are problems with the mode of operand[3]. The point of this
3644: ;; is to represent an HImode move to a "high byte" register.
3645:
3646: (define_expand "insv"
3647: [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "")
3648: (match_operand:SI 1 "immediate_operand" "")
3649: (match_operand:SI 2 "immediate_operand" ""))
3650: (match_operand:QI 3 "general_operand" "ri"))]
3651: ""
3652: "
3653: {
3654: if (GET_CODE (operands[1]) != CONST_INT
3655: || GET_CODE (operands[2]) != CONST_INT)
3656: FAIL;
3657:
3658: if (! (INTVAL (operands[1]) == 8
3659: && (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 0))
3660: && ! INTVAL (operands[1]) == 1)
3661: FAIL;
3662: }")
3663:
3664: ;; ??? Are these constraints right?
3665: (define_insn ""
3666: [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+&qo")
3667: (const_int 8)
3668: (const_int 8))
3669: (match_operand:QI 1 "general_operand" "qn"))]
3670: ""
3671: "*
3672: {
3673: if (REG_P (operands[0]))
3674: return AS2 (mov%B0,%1,%h0);
3675:
3676: operands[0] = adj_offsettable_operand (operands[0], 1);
3677: return AS2 (mov%B0,%1,%0);
3678: }")
3679: */
3680:
3681: ;; On i386, the register count for a bit operation is *not* truncated,
3682: ;; so SHIFT_COUNT_TRUNCATED must not be defined.
3683:
3684: ;; On i486, the shift & or/and code is faster than bts or btr. If
3685: ;; operands[0] is a MEM, the bt[sr] is half as fast as the normal code.
3686:
3687: ;; On i386, bts is a little faster if operands[0] is a reg, and a
3688: ;; little slower if operands[0] is a MEM, than the shift & or/and code.
3689: ;; Use bts & btr, since they reload better.
3690:
3691: ;; General bit set and clear.
3692: (define_insn ""
3693: [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+rm")
3694: (const_int 1)
3695: (match_operand:SI 2 "general_operand" "r"))
3696: (match_operand:SI 3 "const_int_operand" "n"))]
3697: "! TARGET_486 && GET_CODE (operands[2]) != CONST_INT"
3698: "*
3699: {
3700: CC_STATUS_INIT;
3701:
3702: if (INTVAL (operands[3]) == 1)
3703: return AS2 (bts%L0,%2,%0);
3704: else
3705: return AS2 (btr%L0,%2,%0);
3706: }")
3707:
3708: ;; Bit complement. See comments on previous pattern.
3709: ;; ??? Is this really worthwhile?
3710: (define_insn ""
3711: [(set (match_operand:SI 0 "general_operand" "=rm")
3712: (xor:SI (ashift:SI (const_int 1)
3713: (match_operand:SI 1 "general_operand" "r"))
3714: (match_operand:SI 2 "general_operand" "0")))]
3715: "! TARGET_486 && GET_CODE (operands[1]) != CONST_INT"
3716: "*
3717: {
3718: CC_STATUS_INIT;
3719:
3720: return AS2 (btc%L0,%1,%0);
3721: }")
3722:
3723: (define_insn ""
3724: [(set (match_operand:SI 0 "general_operand" "=rm")
3725: (xor:SI (match_operand:SI 1 "general_operand" "0")
3726: (ashift:SI (const_int 1)
3727: (match_operand:SI 2 "general_operand" "r"))))]
3728: "! TARGET_486 && GET_CODE (operands[2]) != CONST_INT"
3729: "*
3730: {
3731: CC_STATUS_INIT;
3732:
3733: return AS2 (btc%L0,%2,%0);
3734: }")
3735:
3736: ;; Recognizers for bit-test instructions.
3737:
3738: ;; The bt opcode allows a MEM in operands[0]. But on both i386 and
3739: ;; i486, it is faster to copy a MEM to REG and then use bt, than to use
3740: ;; bt on the MEM directly.
3741:
3742: ;; ??? The first argument of a zero_extract must not be reloaded, so
3743: ;; don't allow a MEM in the operand predicate without allowing it in the
3744: ;; constraint.
3745:
3746: (define_insn ""
3747: [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r")
3748: (const_int 1)
3749: (match_operand:SI 1 "general_operand" "r")))]
3750: "GET_CODE (operands[1]) != CONST_INT"
3751: "*
3752: {
3753: cc_status.flags |= CC_Z_IN_NOT_C;
3754: return AS2 (bt%L0,%1,%0);
3755: }")
3756:
3757: (define_insn ""
3758: [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r")
3759: (match_operand:SI 1 "const_int_operand" "n")
3760: (match_operand:SI 2 "const_int_operand" "n")))]
3761: ""
3762: "*
3763: {
3764: unsigned int mask;
3765:
3766: mask = ((1 << INTVAL (operands[1])) - 1) << INTVAL (operands[2]);
3767: operands[1] = GEN_INT (mask);
3768:
3769: if (QI_REG_P (operands[0]))
3770: {
3771: if ((mask & ~0xff) == 0)
3772: {
3773: cc_status.flags |= CC_NOT_NEGATIVE;
3774: return AS2 (test%B0,%1,%b0);
3775: }
3776:
3777: if ((mask & ~0xff00) == 0)
3778: {
3779: cc_status.flags |= CC_NOT_NEGATIVE;
3780: operands[1] = GEN_INT (mask >> 8);
3781: return AS2 (test%B0,%1,%h0);
3782: }
3783: }
3784:
3785: return AS2 (test%L0,%1,%0);
3786: }")
3787:
3788: ;; ??? All bets are off if operand 0 is a volatile MEM reference.
3789: ;; The CPU may access unspecified bytes around the actual target byte.
3790:
3791: (define_insn ""
3792: [(set (cc0) (zero_extract (match_operand:QI 0 "general_operand" "rm")
3793: (match_operand:SI 1 "const_int_operand" "n")
3794: (match_operand:SI 2 "const_int_operand" "n")))]
3795: "GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0])"
3796: "*
3797: {
3798: unsigned int mask;
3799:
3800: mask = ((1 << INTVAL (operands[1])) - 1) << INTVAL (operands[2]);
3801: operands[1] = GEN_INT (mask);
3802:
3803: if (! REG_P (operands[0]) || QI_REG_P (operands[0]))
3804: {
3805: if ((mask & ~0xff) == 0)
3806: {
3807: cc_status.flags |= CC_NOT_NEGATIVE;
3808: return AS2 (test%B0,%1,%b0);
3809: }
3810:
3811: if ((mask & ~0xff00) == 0)
3812: {
3813: cc_status.flags |= CC_NOT_NEGATIVE;
3814: operands[1] = GEN_INT (mask >> 8);
3815:
3816: if (QI_REG_P (operands[0]))
3817: return AS2 (test%B0,%1,%h0);
3818: else
3819: {
3820: operands[0] = adj_offsettable_operand (operands[0], 1);
3821: return AS2 (test%B0,%1,%b0);
3822: }
3823: }
3824:
3825: if (GET_CODE (operands[0]) == MEM && (mask & ~0xff0000) == 0)
3826: {
3827: cc_status.flags |= CC_NOT_NEGATIVE;
3828: operands[1] = GEN_INT (mask >> 16);
3829: operands[0] = adj_offsettable_operand (operands[0], 2);
3830: return AS2 (test%B0,%1,%b0);
3831: }
3832:
3833: if (GET_CODE (operands[0]) == MEM && (mask & ~0xff000000) == 0)
3834: {
3835: cc_status.flags |= CC_NOT_NEGATIVE;
3836: operands[1] = GEN_INT (mask >> 24);
3837: operands[0] = adj_offsettable_operand (operands[0], 3);
3838: return AS2 (test%B0,%1,%b0);
3839: }
3840: }
3841:
3842: if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
3843: return AS2 (test%L0,%1,%0);
3844:
3845: return AS2 (test%L1,%0,%1);
3846: }")
3847:
3848: ;; Store-flag instructions.
3849:
3850: ;; For all sCOND expanders, also expand the compare or test insn that
3851: ;; generates cc0. Generate an equality comparison if `seq' or `sne'.
3852:
3853: ;; The 386 sCOND opcodes can write to memory. But a gcc sCOND insn may
3854: ;; not have any input reloads. A MEM write might need an input reload
3855: ;; for the address of the MEM. So don't allow MEM as the SET_DEST.
3856:
3857: (define_expand "seq"
3858: [(match_dup 1)
3859: (set (match_operand:QI 0 "register_operand" "")
3860: (eq:QI (cc0) (const_int 0)))]
3861: ""
3862: "
3863: {
3864: if (TARGET_IEEE_FP
3865: && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
3866: operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
3867: else
3868: operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
3869: }")
3870:
3871: (define_insn ""
3872: [(set (match_operand:QI 0 "register_operand" "=q")
3873: (eq:QI (cc0) (const_int 0)))]
3874: ""
3875: "*
3876: {
3877: if (cc_prev_status.flags & CC_Z_IN_NOT_C)
3878: return AS1 (setnb,%0);
3879: else
3880: return AS1 (sete,%0);
3881: }")
3882:
3883: (define_expand "sne"
3884: [(match_dup 1)
3885: (set (match_operand:QI 0 "register_operand" "")
3886: (ne:QI (cc0) (const_int 0)))]
3887: ""
3888: "
3889: {
3890: if (TARGET_IEEE_FP
3891: && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
3892: operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
3893: else
3894: operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
3895: }")
3896:
3897: (define_insn ""
3898: [(set (match_operand:QI 0 "register_operand" "=q")
3899: (ne:QI (cc0) (const_int 0)))]
3900: ""
3901: "*
3902: {
3903: if (cc_prev_status.flags & CC_Z_IN_NOT_C)
3904: return AS1 (setb,%0);
3905: else
3906: return AS1 (setne,%0);
3907: }
3908: ")
3909:
3910: (define_expand "sgt"
3911: [(match_dup 1)
3912: (set (match_operand:QI 0 "register_operand" "")
3913: (gt:QI (cc0) (const_int 0)))]
3914: ""
3915: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
3916:
3917: (define_insn ""
3918: [(set (match_operand:QI 0 "register_operand" "=q")
3919: (gt:QI (cc0) (const_int 0)))]
3920: ""
3921: "*
3922: {
3923: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
3924: return AS1 (sete,%0);
3925:
3926: OUTPUT_JUMP (\"setg %0\", \"seta %0\", NULL_PTR);
3927: }")
3928:
3929: (define_expand "sgtu"
3930: [(match_dup 1)
3931: (set (match_operand:QI 0 "register_operand" "")
3932: (gtu:QI (cc0) (const_int 0)))]
3933: ""
3934: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
3935:
3936: (define_insn ""
3937: [(set (match_operand:QI 0 "register_operand" "=q")
3938: (gtu:QI (cc0) (const_int 0)))]
3939: ""
3940: "* return \"seta %0\"; ")
3941:
3942: (define_expand "slt"
3943: [(match_dup 1)
3944: (set (match_operand:QI 0 "register_operand" "")
3945: (lt:QI (cc0) (const_int 0)))]
3946: ""
3947: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
3948:
3949: (define_insn ""
3950: [(set (match_operand:QI 0 "register_operand" "=q")
3951: (lt:QI (cc0) (const_int 0)))]
3952: ""
3953: "*
3954: {
3955: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
3956: return AS1 (sete,%0);
3957:
3958: OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %0\");
3959: }")
3960:
3961: (define_expand "sltu"
3962: [(match_dup 1)
3963: (set (match_operand:QI 0 "register_operand" "")
3964: (ltu:QI (cc0) (const_int 0)))]
3965: ""
3966: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
3967:
3968: (define_insn ""
3969: [(set (match_operand:QI 0 "register_operand" "=q")
3970: (ltu:QI (cc0) (const_int 0)))]
3971: ""
3972: "* return \"setb %0\"; ")
3973:
3974: (define_expand "sge"
3975: [(match_dup 1)
3976: (set (match_operand:QI 0 "register_operand" "")
3977: (ge:QI (cc0) (const_int 0)))]
3978: ""
3979: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
3980:
3981: (define_insn ""
3982: [(set (match_operand:QI 0 "register_operand" "=q")
3983: (ge:QI (cc0) (const_int 0)))]
3984: ""
3985: "*
3986: {
3987: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
3988: return AS1 (sete,%0);
3989:
3990: OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %0\");
3991: }")
3992:
3993: (define_expand "sgeu"
3994: [(match_dup 1)
3995: (set (match_operand:QI 0 "register_operand" "")
3996: (geu:QI (cc0) (const_int 0)))]
3997: ""
3998: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
3999:
4000: (define_insn ""
4001: [(set (match_operand:QI 0 "register_operand" "=q")
4002: (geu:QI (cc0) (const_int 0)))]
4003: ""
4004: "* return \"setae %0\"; ")
4005:
4006: (define_expand "sle"
4007: [(match_dup 1)
4008: (set (match_operand:QI 0 "register_operand" "")
4009: (le:QI (cc0) (const_int 0)))]
4010: ""
4011: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
4012:
4013: (define_insn ""
4014: [(set (match_operand:QI 0 "register_operand" "=q")
4015: (le:QI (cc0) (const_int 0)))]
4016: ""
4017: "*
4018: {
4019: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
4020: return AS1 (setb,%0);
4021:
4022: OUTPUT_JUMP (\"setle %0\", \"setbe %0\", NULL_PTR);
4023: }")
4024:
4025: (define_expand "sleu"
4026: [(match_dup 1)
4027: (set (match_operand:QI 0 "register_operand" "")
4028: (leu:QI (cc0) (const_int 0)))]
4029: ""
4030: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
4031:
4032: (define_insn ""
4033: [(set (match_operand:QI 0 "register_operand" "=q")
4034: (leu:QI (cc0) (const_int 0)))]
4035: ""
4036: "* return \"setbe %0\"; ")
4037:
4038: ;; Basic conditional jump instructions.
4039: ;; We ignore the overflow flag for signed branch instructions.
4040:
4041: ;; For all bCOND expanders, also expand the compare or test insn that
4042: ;; generates cc0. Generate an equality comparison if `beq' or `bne'.
4043:
4044: (define_expand "beq"
4045: [(match_dup 1)
4046: (set (pc)
4047: (if_then_else (eq (cc0)
4048: (const_int 0))
4049: (label_ref (match_operand 0 "" ""))
4050: (pc)))]
4051: ""
4052: "
4053: {
4054: if (TARGET_IEEE_FP
4055: && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
4056: operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
4057: else
4058: operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
4059: }")
4060:
4061: (define_insn ""
4062: [(set (pc)
4063: (if_then_else (eq (cc0)
4064: (const_int 0))
4065: (label_ref (match_operand 0 "" ""))
4066: (pc)))]
4067: ""
4068: "*
4069: {
4070: if (cc_prev_status.flags & CC_Z_IN_NOT_C)
4071: return \"jnc %l0\";
4072: else
4073: return \"je %l0\";
4074: }")
4075:
4076: (define_expand "bne"
4077: [(match_dup 1)
4078: (set (pc)
4079: (if_then_else (ne (cc0)
4080: (const_int 0))
4081: (label_ref (match_operand 0 "" ""))
4082: (pc)))]
4083: ""
4084: "
4085: {
4086: if (TARGET_IEEE_FP
4087: && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
4088: operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
4089: else
4090: operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
4091: }")
4092:
4093: (define_insn ""
4094: [(set (pc)
4095: (if_then_else (ne (cc0)
4096: (const_int 0))
4097: (label_ref (match_operand 0 "" ""))
4098: (pc)))]
4099: ""
4100: "*
4101: {
4102: if (cc_prev_status.flags & CC_Z_IN_NOT_C)
4103: return \"jc %l0\";
4104: else
4105: return \"jne %l0\";
4106: }")
4107:
4108: (define_expand "bgt"
4109: [(match_dup 1)
4110: (set (pc)
4111: (if_then_else (gt (cc0)
4112: (const_int 0))
4113: (label_ref (match_operand 0 "" ""))
4114: (pc)))]
4115: ""
4116: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
4117:
4118: (define_insn ""
4119: [(set (pc)
4120: (if_then_else (gt (cc0)
4121: (const_int 0))
4122: (label_ref (match_operand 0 "" ""))
4123: (pc)))]
4124: ""
4125: "*
4126: {
4127: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
4128: return AS1 (je,%l0);
4129:
4130: OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", NULL_PTR);
4131: }")
4132:
4133: (define_expand "bgtu"
4134: [(match_dup 1)
4135: (set (pc)
4136: (if_then_else (gtu (cc0)
4137: (const_int 0))
4138: (label_ref (match_operand 0 "" ""))
4139: (pc)))]
4140: ""
4141: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
4142:
4143: (define_insn ""
4144: [(set (pc)
4145: (if_then_else (gtu (cc0)
4146: (const_int 0))
4147: (label_ref (match_operand 0 "" ""))
4148: (pc)))]
4149: ""
4150: "ja %l0")
4151:
4152: (define_expand "blt"
4153: [(match_dup 1)
4154: (set (pc)
4155: (if_then_else (lt (cc0)
4156: (const_int 0))
4157: (label_ref (match_operand 0 "" ""))
4158: (pc)))]
4159: ""
4160: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
4161:
4162: (define_insn ""
4163: [(set (pc)
4164: (if_then_else (lt (cc0)
4165: (const_int 0))
4166: (label_ref (match_operand 0 "" ""))
4167: (pc)))]
4168: ""
4169: "*
4170: {
4171: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
4172: return AS1 (je,%l0);
4173:
4174: OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\");
4175: }")
4176:
4177: (define_expand "bltu"
4178: [(match_dup 1)
4179: (set (pc)
4180: (if_then_else (ltu (cc0)
4181: (const_int 0))
4182: (label_ref (match_operand 0 "" ""))
4183: (pc)))]
4184: ""
4185: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
4186:
4187: (define_insn ""
4188: [(set (pc)
4189: (if_then_else (ltu (cc0)
4190: (const_int 0))
4191: (label_ref (match_operand 0 "" ""))
4192: (pc)))]
4193: ""
4194: "jb %l0")
4195:
4196: (define_expand "bge"
4197: [(match_dup 1)
4198: (set (pc)
4199: (if_then_else (ge (cc0)
4200: (const_int 0))
4201: (label_ref (match_operand 0 "" ""))
4202: (pc)))]
4203: ""
4204: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
4205:
4206: (define_insn ""
4207: [(set (pc)
4208: (if_then_else (ge (cc0)
4209: (const_int 0))
4210: (label_ref (match_operand 0 "" ""))
4211: (pc)))]
4212: ""
4213: "*
4214: {
4215: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
4216: return AS1 (je,%l0);
4217:
4218: OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\");
4219: }")
4220:
4221: (define_expand "bgeu"
4222: [(match_dup 1)
4223: (set (pc)
4224: (if_then_else (geu (cc0)
4225: (const_int 0))
4226: (label_ref (match_operand 0 "" ""))
4227: (pc)))]
4228: ""
4229: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
4230:
4231: (define_insn ""
4232: [(set (pc)
4233: (if_then_else (geu (cc0)
4234: (const_int 0))
4235: (label_ref (match_operand 0 "" ""))
4236: (pc)))]
4237: ""
4238: "jae %l0")
4239:
4240: (define_expand "ble"
4241: [(match_dup 1)
4242: (set (pc)
4243: (if_then_else (le (cc0)
4244: (const_int 0))
4245: (label_ref (match_operand 0 "" ""))
4246: (pc)))]
4247: ""
4248: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
4249:
4250: (define_insn ""
4251: [(set (pc)
4252: (if_then_else (le (cc0)
4253: (const_int 0))
4254: (label_ref (match_operand 0 "" ""))
4255: (pc)))]
4256: ""
4257: "*
4258: {
4259: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
4260: return AS1 (jb,%l0);
4261:
4262: OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", NULL_PTR);
4263: }")
4264:
4265: (define_expand "bleu"
4266: [(match_dup 1)
4267: (set (pc)
4268: (if_then_else (leu (cc0)
4269: (const_int 0))
4270: (label_ref (match_operand 0 "" ""))
4271: (pc)))]
4272: ""
4273: "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
4274:
4275: (define_insn ""
4276: [(set (pc)
4277: (if_then_else (leu (cc0)
4278: (const_int 0))
4279: (label_ref (match_operand 0 "" ""))
4280: (pc)))]
4281: ""
4282: "jbe %l0")
4283:
4284: ;; Negated conditional jump instructions.
4285:
4286: (define_insn ""
4287: [(set (pc)
4288: (if_then_else (eq (cc0)
4289: (const_int 0))
4290: (pc)
4291: (label_ref (match_operand 0 "" ""))))]
4292: ""
4293: "*
4294: {
4295: if (cc_prev_status.flags & CC_Z_IN_NOT_C)
4296: return \"jc %l0\";
4297: else
4298: return \"jne %l0\";
4299: }")
4300:
4301: (define_insn ""
4302: [(set (pc)
4303: (if_then_else (ne (cc0)
4304: (const_int 0))
4305: (pc)
4306: (label_ref (match_operand 0 "" ""))))]
4307: ""
4308: "*
4309: {
4310: if (cc_prev_status.flags & CC_Z_IN_NOT_C)
4311: return \"jnc %l0\";
4312: else
4313: return \"je %l0\";
4314: }")
4315:
4316: (define_insn ""
4317: [(set (pc)
4318: (if_then_else (gt (cc0)
4319: (const_int 0))
4320: (pc)
4321: (label_ref (match_operand 0 "" ""))))]
4322: ""
4323: "*
4324: {
4325: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
4326: return AS1 (jne,%l0);
4327:
4328: OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", NULL_PTR);
4329: }")
4330:
4331: (define_insn ""
4332: [(set (pc)
4333: (if_then_else (gtu (cc0)
4334: (const_int 0))
4335: (pc)
4336: (label_ref (match_operand 0 "" ""))))]
4337: ""
4338: "jbe %l0")
4339:
4340: (define_insn ""
4341: [(set (pc)
4342: (if_then_else (lt (cc0)
4343: (const_int 0))
4344: (pc)
4345: (label_ref (match_operand 0 "" ""))))]
4346: ""
4347: "*
4348: {
4349: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
4350: return AS1 (jne,%l0);
4351:
4352: OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\");
4353: }")
4354:
4355: (define_insn ""
4356: [(set (pc)
4357: (if_then_else (ltu (cc0)
4358: (const_int 0))
4359: (pc)
4360: (label_ref (match_operand 0 "" ""))))]
4361: ""
4362: "jae %l0")
4363:
4364: (define_insn ""
4365: [(set (pc)
4366: (if_then_else (ge (cc0)
4367: (const_int 0))
4368: (pc)
4369: (label_ref (match_operand 0 "" ""))))]
4370: ""
4371: "*
4372: {
4373: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
4374: return AS1 (jne,%l0);
4375:
4376: OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\");
4377: }")
4378:
4379: (define_insn ""
4380: [(set (pc)
4381: (if_then_else (geu (cc0)
4382: (const_int 0))
4383: (pc)
4384: (label_ref (match_operand 0 "" ""))))]
4385: ""
4386: "jb %l0")
4387:
4388: (define_insn ""
4389: [(set (pc)
4390: (if_then_else (le (cc0)
4391: (const_int 0))
4392: (pc)
4393: (label_ref (match_operand 0 "" ""))))]
4394: ""
4395: "*
4396: {
4397: if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
4398: return AS1 (jae,%l0);
4399:
4400: OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", NULL_PTR);
4401: }")
4402:
4403: (define_insn ""
4404: [(set (pc)
4405: (if_then_else (leu (cc0)
4406: (const_int 0))
4407: (pc)
4408: (label_ref (match_operand 0 "" ""))))]
4409: ""
4410: "ja %l0")
4411:
4412: ;; Unconditional and other jump instructions
4413:
4414: (define_insn "jump"
4415: [(set (pc)
4416: (label_ref (match_operand 0 "" "")))]
4417: ""
4418: "jmp %l0")
4419:
4420: (define_insn "indirect_jump"
4421: [(set (pc) (match_operand:SI 0 "general_operand" "rm"))]
4422: ""
4423: "*
4424: {
4425: CC_STATUS_INIT;
4426:
4427: return AS1 (jmp,%*%0);
4428: }")
4429:
4430: ;; Implement switch statements when generating PIC code. Switches are
4431: ;; implemented by `tablejump' when not using -fpic.
4432:
4433: ;; Emit code here to do the range checking and make the index zero based.
4434:
4435: (define_expand "casesi"
4436: [(set (match_dup 5)
4437: (minus:SI (match_operand:SI 0 "general_operand" "")
4438: (match_operand:SI 1 "general_operand" "")))
4439: (set (cc0)
4440: (compare:CC (match_dup 5)
4441: (match_operand:SI 2 "general_operand" "")))
4442: (set (pc)
4443: (if_then_else (gtu (cc0)
4444: (const_int 0))
4445: (label_ref (match_operand 4 "" ""))
4446: (pc)))
4447: (parallel
4448: [(set (pc)
4449: (minus:SI (reg:SI 3)
4450: (mem:SI (plus:SI (mult:SI (match_dup 5)
4451: (const_int 4))
4452: (label_ref (match_operand 3 "" ""))))))
4453: (clobber (match_scratch:SI 6 ""))])]
4454: "flag_pic"
4455: "
4456: {
4457: operands[5] = gen_reg_rtx (SImode);
4458: current_function_uses_pic_offset_table = 1;
4459: }")
4460:
4461: ;; Implement a casesi insn.
4462:
4463: ;; Each entry in the "addr_diff_vec" looks like this as the result of the
4464: ;; two rules below:
4465: ;;
4466: ;; .long _GLOBAL_OFFSET_TABLE_+[.-.L2]
4467: ;;
4468: ;; 1. An expression involving an external reference may only use the
4469: ;; addition operator, and only with an assembly-time constant.
4470: ;; The example above satisfies this because ".-.L2" is a constant.
4471: ;;
4472: ;; 2. The symbol _GLOBAL_OFFSET_TABLE_ is magic, and at link time is
4473: ;; given the value of "GOT - .", where GOT is the actual address of
4474: ;; the Global Offset Table. Therefore, the .long above actually
4475: ;; stores the value "( GOT - . ) + [ . - .L2 ]", or "GOT - .L2". The
4476: ;; expression "GOT - .L2" by itself would generate an error from as(1).
4477: ;;
4478: ;; The pattern below emits code that looks like this:
4479: ;;
4480: ;; movl %ebx,reg
4481: ;; subl TABLE@GOTOFF(%ebx,index,4),reg
4482: ;; jmp reg
4483: ;;
4484: ;; The addr_diff_vec contents may be directly referenced with @GOTOFF, since
4485: ;; the addr_diff_vec is known to be part of this module.
4486: ;;
4487: ;; The subl above calculates "GOT - (( GOT - . ) + [ . - .L2 ])", which
4488: ;; evaluates to just ".L2".
4489:
4490: (define_insn ""
4491: [(set (pc)
4492: (minus:SI (reg:SI 3)
4493: (mem:SI (plus:SI
4494: (mult:SI (match_operand:SI 0 "register_operand" "r")
4495: (const_int 4))
4496: (label_ref (match_operand 1 "" ""))))))
4497: (clobber (match_scratch:SI 2 "=&r"))]
4498: ""
4499: "*
4500: {
4501: rtx xops[4];
4502:
4503: xops[0] = operands[0];
4504: xops[1] = operands[1];
4505: xops[2] = operands[2];
4506: xops[3] = pic_offset_table_rtx;
4507:
4508: output_asm_insn (AS2 (mov%L2,%3,%2), xops);
4509: output_asm_insn (\"sub%L2 %l1@GOTOFF(%3,%0,4),%2\", xops);
4510: output_asm_insn (AS1 (jmp,%*%2), xops);
4511: ASM_OUTPUT_ALIGN_CODE (asm_out_file);
4512: RET;
4513: }")
4514:
4515: (define_insn "tablejump"
4516: [(set (pc) (match_operand:SI 0 "general_operand" "rm"))
4517: (use (label_ref (match_operand 1 "" "")))]
4518: ""
4519: "*
4520: {
4521: CC_STATUS_INIT;
4522:
4523: return AS1 (jmp,%*%0);
4524: }")
4525:
4526: ;; Call insns.
4527:
4528: ;; If generating PIC code, the predicate indirect_operand will fail
4529: ;; for operands[0] containing symbolic references on all of the named
4530: ;; call* patterns. Each named pattern is followed by an unnamed pattern
4531: ;; that matches any call to a symbolic CONST (ie, a symbol_ref). The
4532: ;; unnamed patterns are only used while generating PIC code, because
4533: ;; otherwise the named patterns match.
4534:
4535: ;; Call subroutine returning no value.
4536:
4537: (define_expand "call_pop"
4538: [(parallel [(call (match_operand:QI 0 "indirect_operand" "")
4539: (match_operand:SI 1 "general_operand" ""))
4540: (set (reg:SI 7)
4541: (plus:SI (reg:SI 7)
4542: (match_operand:SI 3 "immediate_operand" "")))])]
4543: ""
4544: "
4545: {
4546: rtx addr;
4547:
4548: if (flag_pic)
4549: current_function_uses_pic_offset_table = 1;
4550:
4551: /* With half-pic, force the address into a register. */
4552: addr = XEXP (operands[0], 0);
4553: if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
4554: XEXP (operands[0], 0) = force_reg (Pmode, addr);
4555:
4556: if (! expander_call_insn_operand (operands[0], QImode))
4557: operands[0]
4558: = change_address (operands[0], VOIDmode,
4559: copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
4560: }")
4561:
4562: (define_insn ""
4563: [(call (match_operand:QI 0 "call_insn_operand" "m")
4564: (match_operand:SI 1 "general_operand" "g"))
4565: (set (reg:SI 7) (plus:SI (reg:SI 7)
4566: (match_operand:SI 3 "immediate_operand" "i")))]
4567: ""
4568: "*
4569: {
4570: if (GET_CODE (operands[0]) == MEM
4571: && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
4572: {
4573: operands[0] = XEXP (operands[0], 0);
4574: return AS1 (call,%*%0);
4575: }
4576: else
4577: return AS1 (call,%P0);
4578: }")
4579:
4580: (define_insn ""
4581: [(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
4582: (match_operand:SI 1 "general_operand" "g"))
4583: (set (reg:SI 7) (plus:SI (reg:SI 7)
4584: (match_operand:SI 3 "immediate_operand" "i")))]
4585: "!HALF_PIC_P ()"
4586: "call %P0")
4587:
4588: (define_expand "call"
4589: [(call (match_operand:QI 0 "indirect_operand" "")
4590: (match_operand:SI 1 "general_operand" ""))]
4591: ;; Operand 1 not used on the i386.
4592: ""
4593: "
4594: {
4595: rtx addr;
4596:
4597: if (flag_pic)
4598: current_function_uses_pic_offset_table = 1;
4599:
4600: /* With half-pic, force the address into a register. */
4601: addr = XEXP (operands[0], 0);
4602: if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
4603: XEXP (operands[0], 0) = force_reg (Pmode, addr);
4604:
4605: if (! expander_call_insn_operand (operands[0], QImode))
4606: operands[0]
4607: = change_address (operands[0], VOIDmode,
4608: copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
4609: }")
4610:
4611: (define_insn ""
4612: [(call (match_operand:QI 0 "call_insn_operand" "m")
4613: (match_operand:SI 1 "general_operand" "g"))]
4614: ;; Operand 1 not used on the i386.
4615: ""
4616: "*
4617: {
4618: if (GET_CODE (operands[0]) == MEM
4619: && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
4620: {
4621: operands[0] = XEXP (operands[0], 0);
4622: return AS1 (call,%*%0);
4623: }
4624: else
4625: return AS1 (call,%P0);
4626: }")
4627:
4628: (define_insn ""
4629: [(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
4630: (match_operand:SI 1 "general_operand" "g"))]
4631: ;; Operand 1 not used on the i386.
4632: "!HALF_PIC_P ()"
4633: "call %P0")
4634:
4635: ;; Call subroutine, returning value in operand 0
4636: ;; (which must be a hard register).
4637:
4638: (define_expand "call_value_pop"
4639: [(parallel [(set (match_operand 0 "" "")
4640: (call (match_operand:QI 1 "indirect_operand" "")
4641: (match_operand:SI 2 "general_operand" "")))
4642: (set (reg:SI 7)
4643: (plus:SI (reg:SI 7)
4644: (match_operand:SI 4 "immediate_operand" "")))])]
4645: ""
4646: "
4647: {
4648: rtx addr;
4649:
4650: if (flag_pic)
4651: current_function_uses_pic_offset_table = 1;
4652:
4653: /* With half-pic, force the address into a register. */
4654: addr = XEXP (operands[1], 0);
4655: if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
4656: XEXP (operands[1], 0) = force_reg (Pmode, addr);
4657:
4658: if (! expander_call_insn_operand (operands[1], QImode))
4659: operands[1]
4660: = change_address (operands[1], VOIDmode,
4661: copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
4662: }")
4663:
4664: (define_insn ""
4665: [(set (match_operand 0 "" "=rf")
4666: (call (match_operand:QI 1 "call_insn_operand" "m")
4667: (match_operand:SI 2 "general_operand" "g")))
4668: (set (reg:SI 7) (plus:SI (reg:SI 7)
4669: (match_operand:SI 4 "immediate_operand" "i")))]
4670: ""
4671: "*
4672: {
4673: if (GET_CODE (operands[1]) == MEM
4674: && ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
4675: {
4676: operands[1] = XEXP (operands[1], 0);
4677: output_asm_insn (AS1 (call,%*%1), operands);
4678: }
4679: else
4680: output_asm_insn (AS1 (call,%P1), operands);
4681:
4682: RET;
4683: }")
4684:
4685: (define_insn ""
4686: [(set (match_operand 0 "" "=rf")
4687: (call (mem:QI (match_operand:SI 1 "symbolic_operand" ""))
4688: (match_operand:SI 2 "general_operand" "g")))
4689: (set (reg:SI 7) (plus:SI (reg:SI 7)
4690: (match_operand:SI 4 "immediate_operand" "i")))]
4691: "!HALF_PIC_P ()"
4692: "call %P1")
4693:
4694: (define_expand "call_value"
4695: [(set (match_operand 0 "" "")
4696: (call (match_operand:QI 1 "indirect_operand" "")
4697: (match_operand:SI 2 "general_operand" "")))]
4698: ;; Operand 2 not used on the i386.
4699: ""
4700: "
4701: {
4702: rtx addr;
4703:
4704: if (flag_pic)
4705: current_function_uses_pic_offset_table = 1;
4706:
4707: /* With half-pic, force the address into a register. */
4708: addr = XEXP (operands[1], 0);
4709: if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
4710: XEXP (operands[1], 0) = force_reg (Pmode, addr);
4711:
4712: if (! expander_call_insn_operand (operands[1], QImode))
4713: operands[1]
4714: = change_address (operands[1], VOIDmode,
4715: copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
4716: }")
4717:
4718: (define_insn ""
4719: [(set (match_operand 0 "" "=rf")
4720: (call (match_operand:QI 1 "call_insn_operand" "m")
4721: (match_operand:SI 2 "general_operand" "g")))]
4722: ;; Operand 2 not used on the i386.
4723: ""
4724: "*
4725: {
4726: if (GET_CODE (operands[1]) == MEM
4727: && ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
4728: {
4729: operands[1] = XEXP (operands[1], 0);
4730: output_asm_insn (AS1 (call,%*%1), operands);
4731: }
4732: else
4733: output_asm_insn (AS1 (call,%P1), operands);
4734:
4735: RET;
4736: }")
4737:
4738: (define_insn ""
4739: [(set (match_operand 0 "" "=rf")
4740: (call (mem:QI (match_operand:SI 1 "symbolic_operand" ""))
4741: (match_operand:SI 2 "general_operand" "g")))]
4742: ;; Operand 2 not used on the i386.
4743: "!HALF_PIC_P ()"
4744: "call %P1")
4745:
4746: (define_expand "untyped_call"
4747: [(parallel [(call (match_operand:QI 0 "indirect_operand" "")
4748: (const_int 0))
4749: (match_operand:BLK 1 "memory_operand" "")
4750: (match_operand 2 "" "")])]
4751: ""
4752: "
4753: {
4754: rtx addr;
4755:
4756: if (flag_pic)
4757: current_function_uses_pic_offset_table = 1;
4758:
4759: /* With half-pic, force the address into a register. */
4760: addr = XEXP (operands[0], 0);
4761: if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
4762: XEXP (operands[0], 0) = force_reg (Pmode, addr);
4763:
4764: operands[1] = change_address (operands[1], DImode, XEXP (operands[1], 0));
4765: if (! expander_call_insn_operand (operands[1], QImode))
4766: operands[1]
4767: = change_address (operands[1], VOIDmode,
4768: copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
4769: }")
4770:
4771: (define_insn ""
4772: [(call (match_operand:QI 0 "call_insn_operand" "m")
4773: (const_int 0))
4774: (match_operand:DI 1 "memory_operand" "o")
4775: (match_operand 2 "" "")]
4776: ""
4777: "*
4778: {
4779: rtx addr = operands[1];
4780:
4781: if (GET_CODE (operands[0]) == MEM
4782: && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
4783: {
4784: operands[0] = XEXP (operands[0], 0);
4785: output_asm_insn (AS1 (call,%*%0), operands);
4786: }
4787: else
4788: output_asm_insn (AS1 (call,%P0), operands);
4789:
4790: operands[2] = gen_rtx (REG, SImode, 0);
4791: output_asm_insn (AS2 (mov%L2,%2,%1), operands);
4792:
4793: operands[2] = gen_rtx (REG, SImode, 1);
4794: operands[1] = adj_offsettable_operand (addr, 4);
4795: output_asm_insn (AS2 (mov%L2,%2,%1), operands);
4796:
4797: operands[1] = adj_offsettable_operand (addr, 8);
4798: return AS1 (fnsave,%1);
4799: }")
4800:
4801: (define_insn ""
4802: [(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
4803: (const_int 0))
4804: (match_operand:DI 1 "memory_operand" "o")
4805: (match_operand 2 "" "")]
4806: "!HALF_PIC_P ()"
4807: "*
4808: {
4809: rtx addr = operands[1];
4810:
4811: output_asm_insn (AS1 (call,%P0), operands);
4812:
4813: operands[2] = gen_rtx (REG, SImode, 0);
4814: output_asm_insn (AS2 (mov%L2,%2,%1), operands);
4815:
4816: operands[2] = gen_rtx (REG, SImode, 1);
4817: operands[1] = adj_offsettable_operand (addr, 4);
4818: output_asm_insn (AS2 (mov%L2,%2,%1), operands);
4819:
4820: operands[1] = adj_offsettable_operand (addr, 8);
4821: return AS1 (fnsave,%1);
4822: }")
4823:
4824: ;; We use fnsave and frstor to save and restore the floating point result.
4825: ;; These are expensive instructions and require a large space to save the
4826: ;; FPU state. An more complicated alternative is to use fnstenv to store
4827: ;; the FPU environment and test whether the stack top is valid. Store the
4828: ;; result of the test, and if it is valid, pop and save the value. The
4829: ;; untyped_return would check the test and optionally push the saved value.
4830:
4831: (define_expand "untyped_return"
4832: [(match_operand:BLK 0 "memory_operand" "")
4833: (match_operand 1 "" "")]
4834: ""
4835: "
4836: {
4837: rtx valreg1 = gen_rtx (REG, SImode, 0);
4838: rtx valreg2 = gen_rtx (REG, SImode, 1);
4839: rtx result = operands[0];
4840:
4841: /* Restore the FPU state. */
4842: emit_insn (gen_update_return (change_address (result, SImode,
4843: plus_constant (XEXP (result, 0),
4844: 8))));
4845:
4846: /* Reload the function value registers. */
4847: emit_move_insn (valreg1, change_address (result, SImode, XEXP (result, 0)));
4848: emit_move_insn (valreg2,
4849: change_address (result, SImode,
4850: plus_constant (XEXP (result, 0), 4)));
4851:
4852: /* Put USE insns before the return. */
4853: emit_insn (gen_rtx (USE, VOIDmode, valreg1));
4854: emit_insn (gen_rtx (USE, VOIDmode, valreg2));
4855:
4856: /* Construct the return. */
4857: expand_null_return ();
4858:
4859: DONE;
4860: }")
4861:
4862: (define_insn "update_return"
4863: [(unspec:SI [(match_operand:SI 0 "memory_operand" "m")] 0)]
4864: ""
4865: "frstor %0")
4866:
4867: ;; Insn emitted into the body of a function to return from a function.
4868: ;; This is only done if the function's epilogue is known to be simple.
4869: ;; See comments for simple_386_epilogue in i386.c.
4870:
4871: (define_insn "return"
4872: [(return)]
4873: "simple_386_epilogue ()"
4874: "*
4875: {
4876: function_epilogue (asm_out_file, get_frame_size ());
4877: RET;
4878: }")
4879:
4880: (define_insn "nop"
4881: [(const_int 0)]
4882: ""
4883: "nop")
4884:
4885: (define_expand "movstrsi"
4886: [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
4887: (match_operand:BLK 1 "memory_operand" ""))
4888: (use (match_operand:SI 2 "const_int_operand" ""))
4889: (use (match_operand:SI 3 "const_int_operand" ""))
4890: (clobber (match_scratch:SI 4 ""))
4891: (clobber (match_dup 5))
4892: (clobber (match_dup 6))])]
4893: ""
4894: "
4895: {
4896: rtx addr0, addr1;
4897:
4898: if (GET_CODE (operands[2]) != CONST_INT)
4899: FAIL;
4900:
4901: addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
4902: addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
4903:
4904: operands[5] = addr0;
4905: operands[6] = addr1;
4906:
4907: operands[0] = gen_rtx (MEM, BLKmode, addr0);
4908: operands[1] = gen_rtx (MEM, BLKmode, addr1);
4909: }")
4910:
4911: ;; It might seem that operands 0 & 1 could use predicate register_operand.
4912: ;; But strength reduction might offset the MEM expression. So we let
4913: ;; reload put the address into %edi & %esi.
4914:
4915: (define_insn ""
4916: [(set (mem:BLK (match_operand:SI 0 "address_operand" "D"))
4917: (mem:BLK (match_operand:SI 1 "address_operand" "S")))
4918: (use (match_operand:SI 2 "const_int_operand" "n"))
4919: (use (match_operand:SI 3 "immediate_operand" "i"))
4920: (clobber (match_scratch:SI 4 "=&c"))
4921: (clobber (match_dup 0))
4922: (clobber (match_dup 1))]
4923: ""
4924: "*
4925: {
4926: rtx xops[2];
4927:
4928: output_asm_insn (\"cld\", operands);
4929: if (GET_CODE (operands[2]) == CONST_INT)
4930: {
4931: if (INTVAL (operands[2]) & ~0x03)
4932: {
4933: xops[0] = GEN_INT ((INTVAL (operands[2]) >> 2) & 0x3fffffff);
4934: xops[1] = operands[4];
4935:
4936: output_asm_insn (AS2 (mov%L1,%0,%1), xops);
4937: #ifdef INTEL_SYNTAX
4938: output_asm_insn (\"rep movsd\", xops);
4939: #else
4940: output_asm_insn (\"rep\;movsl\", xops);
4941: #endif
4942: }
4943: if (INTVAL (operands[2]) & 0x02)
4944: output_asm_insn (\"movsw\", operands);
4945: if (INTVAL (operands[2]) & 0x01)
4946: output_asm_insn (\"movsb\", operands);
4947: }
4948: else
4949: abort ();
4950: RET;
4951: }")
4952:
4953: (define_expand "cmpstrsi"
4954: [(parallel [(set (match_operand:SI 0 "general_operand" "")
4955: (compare:SI (match_operand:BLK 1 "general_operand" "")
4956: (match_operand:BLK 2 "general_operand" "")))
4957: (use (match_operand:SI 3 "general_operand" ""))
4958: (use (match_operand:SI 4 "immediate_operand" ""))
4959: (clobber (match_dup 5))
4960: (clobber (match_dup 6))
4961: (clobber (match_dup 3))])]
4962: ""
4963: "
4964: {
4965: rtx addr1, addr2;
4966:
4967: addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
4968: addr2 = copy_to_mode_reg (Pmode, XEXP (operands[2], 0));
4969: operands[3] = copy_to_mode_reg (SImode, operands[3]);
4970:
4971: operands[5] = addr1;
4972: operands[6] = addr2;
4973:
4974: operands[1] = gen_rtx (MEM, BLKmode, addr1);
4975: operands[2] = gen_rtx (MEM, BLKmode, addr2);
4976:
4977: }")
4978:
4979: ;; memcmp recognizers. The `cmpsb' opcode does nothing if the count is
4980: ;; zero. Emit extra code to make sure that a zero-length compare is EQ.
4981:
4982: ;; It might seem that operands 0 & 1 could use predicate register_operand.
4983: ;; But strength reduction might offset the MEM expression. So we let
4984: ;; reload put the address into %edi & %esi.
4985:
4986: ;; ??? Most comparisons have a constant length, and it's therefore
4987: ;; possible to know that the length is non-zero, and to avoid the extra
4988: ;; code to handle zero-length compares.
4989:
4990: (define_insn ""
4991: [(set (match_operand:SI 0 "general_operand" "=&r")
4992: (compare:SI (mem:BLK (match_operand:SI 1 "address_operand" "S"))
4993: (mem:BLK (match_operand:SI 2 "address_operand" "D"))))
4994: (use (match_operand:SI 3 "register_operand" "c"))
4995: (use (match_operand:SI 4 "immediate_operand" "i"))
4996: (clobber (match_dup 1))
4997: (clobber (match_dup 2))
4998: (clobber (match_dup 3))]
4999: ""
5000: "*
5001: {
5002: rtx xops[4], label;
5003:
5004: label = gen_label_rtx ();
5005:
5006: output_asm_insn (\"cld\", operands);
5007: output_asm_insn (AS2 (xor%L0,%0,%0), operands);
5008: output_asm_insn (\"repz\;cmps%B2\", operands);
5009: output_asm_insn (\"je %l0\", &label);
5010:
5011: xops[0] = operands[0];
5012: xops[1] = gen_rtx (MEM, QImode,
5013: gen_rtx (PLUS, SImode, operands[1], constm1_rtx));
5014: xops[2] = gen_rtx (MEM, QImode,
5015: gen_rtx (PLUS, SImode, operands[2], constm1_rtx));
5016: xops[3] = operands[3];
5017:
5018: output_asm_insn (AS2 (movz%B1%L0,%1,%0), xops);
5019: output_asm_insn (AS2 (movz%B2%L3,%2,%3), xops);
5020:
5021: output_asm_insn (AS2 (sub%L0,%3,%0), xops);
5022: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (label));
5023: RET;
5024: }")
5025:
5026: (define_insn ""
5027: [(set (cc0)
5028: (compare:SI (mem:BLK (match_operand:SI 0 "address_operand" "S"))
5029: (mem:BLK (match_operand:SI 1 "address_operand" "D"))))
5030: (use (match_operand:SI 2 "register_operand" "c"))
5031: (use (match_operand:SI 3 "immediate_operand" "i"))
5032: (clobber (match_dup 0))
5033: (clobber (match_dup 1))
5034: (clobber (match_dup 2))]
5035: ""
5036: "*
5037: {
5038: rtx xops[2];
5039:
5040: cc_status.flags |= CC_NOT_SIGNED;
5041:
5042: xops[0] = gen_rtx (REG, QImode, 0);
5043: xops[1] = CONST0_RTX (QImode);
5044:
5045: output_asm_insn (\"cld\", operands);
5046: output_asm_insn (AS2 (test%B0,%1,%0), xops);
5047: return \"repz\;cmps%B2\";
5048: }")
5049:
5050: (define_expand "ffssi2"
5051: [(set (match_dup 2)
5052: (plus:SI (ffs:SI (match_operand:SI 1 "general_operand" ""))
5053: (const_int -1)))
5054: (set (match_operand:SI 0 "general_operand" "")
5055: (plus:SI (match_dup 2) (const_int 1)))]
5056: ""
5057: "operands[2] = gen_reg_rtx (SImode);")
5058:
5059: (define_insn ""
5060: [(set (match_operand:SI 0 "general_operand" "=&r")
5061: (plus:SI (ffs:SI (match_operand:SI 1 "general_operand" "rm"))
5062: (const_int -1)))]
5063: ""
5064: "*
5065: {
5066: rtx xops[3];
5067: static int ffssi_label_number;
5068: char buffer[30];
5069:
5070: xops[0] = operands[0];
5071: xops[1] = operands[1];
5072: xops[2] = constm1_rtx;
5073: /* Can there be a way to avoid the jump here? */
5074: output_asm_insn (AS2 (bsf%L0,%1,%0), xops);
5075: #ifdef LOCAL_LABEL_PREFIX
5076: sprintf (buffer, \"jnz %sLFFSSI%d\",
5077: LOCAL_LABEL_PREFIX, ffssi_label_number);
5078: #else
5079: sprintf (buffer, \"jnz %sLFFSSI%d\",
5080: \"\", ffssi_label_number);
5081: #endif
5082: output_asm_insn (buffer, xops);
5083: output_asm_insn (AS2 (mov%L0,%2,%0), xops);
5084: #ifdef LOCAL_LABEL_PREFIX
5085: sprintf (buffer, \"%sLFFSSI%d:\",
5086: LOCAL_LABEL_PREFIX, ffssi_label_number);
5087: #else
5088: sprintf (buffer, \"%sLFFSSI%d:\",
5089: \"\", ffssi_label_number);
5090: #endif
5091: output_asm_insn (buffer, xops);
5092:
5093: ffssi_label_number++;
5094: return \"\";
5095: }")
5096:
5097: (define_expand "ffshi2"
5098: [(set (match_dup 2)
5099: (plus:HI (ffs:HI (match_operand:HI 1 "general_operand" ""))
5100: (const_int -1)))
5101: (set (match_operand:HI 0 "general_operand" "")
5102: (plus:HI (match_dup 2) (const_int 1)))]
5103: ""
5104: "operands[2] = gen_reg_rtx (HImode);")
5105:
5106: (define_insn ""
5107: [(set (match_operand:HI 0 "general_operand" "=&r")
5108: (plus:HI (ffs:HI (match_operand:SI 1 "general_operand" "rm"))
5109: (const_int -1)))]
5110: ""
5111: "*
5112: {
5113: rtx xops[3];
5114: static int ffshi_label_number;
5115: char buffer[30];
5116:
5117: xops[0] = operands[0];
5118: xops[1] = operands[1];
5119: xops[2] = constm1_rtx;
5120: output_asm_insn (AS2 (bsf%W0,%1,%0), xops);
5121: #ifdef LOCAL_LABEL_PREFIX
5122: sprintf (buffer, \"jnz %sLFFSHI%d\",
5123: LOCAL_LABEL_PREFIX, ffshi_label_number);
5124: #else
5125: sprintf (buffer, \"jnz %sLFFSHI%d\",
5126: \"\", ffshi_label_number);
5127: #endif
5128: output_asm_insn (buffer, xops);
5129: output_asm_insn (AS2 (mov%W0,%2,%0), xops);
5130: #ifdef LOCAL_LABEL_PREFIX
5131: sprintf (buffer, \"%sLFFSHI%d:\",
5132: LOCAL_LABEL_PREFIX, ffshi_label_number);
5133: #else
5134: sprintf (buffer, \"%sLFFSHI%d:\",
5135: \"\", ffshi_label_number);
5136: #endif
5137: output_asm_insn (buffer, xops);
5138:
5139: ffshi_label_number++;
5140: return \"\";
5141: }")
5142:
5143: ;; These patterns match the binary 387 instructions for addM3, subM3,
5144: ;; mulM3 and divM3. There are three patterns for each of DFmode and
5145: ;; SFmode. The first is the normal insn, the second the same insn but
5146: ;; with one operand a conversion, and the third the same insn but with
5147: ;; the other operand a conversion. The conversion may be SFmode or
5148: ;; SImode if the target mode DFmode, but only SImode if the target mode
5149: ;; is SFmode.
5150:
5151: (define_insn ""
5152: [(set (match_operand:DF 0 "register_operand" "=f,f")
5153: (match_operator:DF 3 "binary_387_op"
5154: [(match_operand:DF 1 "nonimmediate_operand" "0,fm")
5155: (match_operand:DF 2 "nonimmediate_operand" "fm,0")]))]
5156: "TARGET_80387"
5157: "* return (char *) output_387_binary_op (insn, operands);")
5158:
5159: (define_insn ""
5160: [(set (match_operand:DF 0 "register_operand" "=f")
5161: (match_operator:DF 3 "binary_387_op"
5162: [(float:DF (match_operand:SI 1 "general_operand" "rm"))
5163: (match_operand:DF 2 "general_operand" "0")]))]
5164: "TARGET_80387"
5165: "* return (char *) output_387_binary_op (insn, operands);")
5166:
5167: (define_insn ""
5168: [(set (match_operand:XF 0 "register_operand" "=f,f")
5169: (match_operator:XF 3 "binary_387_op"
5170: [(match_operand:XF 1 "nonimmediate_operand" "0,f")
5171: (match_operand:XF 2 "nonimmediate_operand" "f,0")]))]
5172: "TARGET_80387"
5173: "* return (char *) output_387_binary_op (insn, operands);")
5174:
5175: (define_insn ""
5176: [(set (match_operand:XF 0 "register_operand" "=f")
5177: (match_operator:XF 3 "binary_387_op"
5178: [(float:XF (match_operand:SI 1 "general_operand" "rm"))
5179: (match_operand:XF 2 "general_operand" "0")]))]
5180: "TARGET_80387"
5181: "* return (char *) output_387_binary_op (insn, operands);")
5182:
5183: (define_insn ""
5184: [(set (match_operand:XF 0 "register_operand" "=f,f")
5185: (match_operator:XF 3 "binary_387_op"
5186: [(float_extend:XF (match_operand:SF 1 "general_operand" "fm,0"))
5187: (match_operand:XF 2 "general_operand" "0,f")]))]
5188: "TARGET_80387"
5189: "* return (char *) output_387_binary_op (insn, operands);")
5190:
5191: (define_insn ""
5192: [(set (match_operand:XF 0 "register_operand" "=f")
5193: (match_operator:XF 3 "binary_387_op"
5194: [(match_operand:XF 1 "general_operand" "0")
5195: (float:XF (match_operand:SI 2 "general_operand" "rm"))]))]
5196: "TARGET_80387"
5197: "* return (char *) output_387_binary_op (insn, operands);")
5198:
5199: (define_insn ""
5200: [(set (match_operand:XF 0 "register_operand" "=f,f")
5201: (match_operator:XF 3 "binary_387_op"
5202: [(match_operand:XF 1 "general_operand" "0,f")
5203: (float_extend:XF
5204: (match_operand:SF 2 "general_operand" "fm,0"))]))]
5205: "TARGET_80387"
5206: "* return (char *) output_387_binary_op (insn, operands);")
5207:
5208: (define_insn ""
5209: [(set (match_operand:DF 0 "register_operand" "=f,f")
5210: (match_operator:DF 3 "binary_387_op"
5211: [(float_extend:DF (match_operand:SF 1 "general_operand" "fm,0"))
5212: (match_operand:DF 2 "general_operand" "0,f")]))]
5213: "TARGET_80387"
5214: "* return (char *) output_387_binary_op (insn, operands);")
5215:
5216: (define_insn ""
5217: [(set (match_operand:DF 0 "register_operand" "=f")
5218: (match_operator:DF 3 "binary_387_op"
5219: [(match_operand:DF 1 "general_operand" "0")
5220: (float:DF (match_operand:SI 2 "general_operand" "rm"))]))]
5221: "TARGET_80387"
5222: "* return (char *) output_387_binary_op (insn, operands);")
5223:
5224: (define_insn ""
5225: [(set (match_operand:DF 0 "register_operand" "=f,f")
5226: (match_operator:DF 3 "binary_387_op"
5227: [(match_operand:DF 1 "general_operand" "0,f")
5228: (float_extend:DF
5229: (match_operand:SF 2 "general_operand" "fm,0"))]))]
5230: "TARGET_80387"
5231: "* return (char *) output_387_binary_op (insn, operands);")
5232:
5233: (define_insn ""
5234: [(set (match_operand:SF 0 "register_operand" "=f,f")
5235: (match_operator:SF 3 "binary_387_op"
5236: [(match_operand:SF 1 "nonimmediate_operand" "0,fm")
5237: (match_operand:SF 2 "nonimmediate_operand" "fm,0")]))]
5238: "TARGET_80387"
5239: "* return (char *) output_387_binary_op (insn, operands);")
5240:
5241: (define_insn ""
5242: [(set (match_operand:SF 0 "register_operand" "=f")
5243: (match_operator:SF 3 "binary_387_op"
5244: [(float:SF (match_operand:SI 1 "general_operand" "rm"))
5245: (match_operand:SF 2 "general_operand" "0")]))]
5246: "TARGET_80387"
5247: "* return (char *) output_387_binary_op (insn, operands);")
5248:
5249: (define_insn ""
5250: [(set (match_operand:SF 0 "register_operand" "=f")
5251: (match_operator:SF 3 "binary_387_op"
5252: [(match_operand:SF 1 "general_operand" "0")
5253: (float:SF (match_operand:SI 2 "general_operand" "rm"))]))]
5254: "TARGET_80387"
5255: "* return (char *) output_387_binary_op (insn, operands);")
5256:
5257: (define_expand "strlensi"
5258: [(parallel [(set (match_dup 4)
5259: (unspec:SI [(mem:BLK (match_operand:BLK 1 "general_operand" ""))
5260: (match_operand:QI 2 "register_operand" "")
5261: (match_operand:SI 3 "immediate_operand" "")] 0))
5262: (clobber (match_dup 1))])
5263: (set (match_dup 5)
5264: (not:SI (match_dup 4)))
5265: (set (match_operand:SI 0 "register_operand" "")
5266: (minus:SI (match_dup 5)
5267: (const_int 1)))]
5268: ""
5269: "
5270: {
5271: operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
5272: operands[4] = gen_reg_rtx (SImode);
5273: operands[5] = gen_reg_rtx (SImode);
5274: }")
5275:
5276: ;; It might seem that operands 0 & 1 could use predicate register_operand.
5277: ;; But strength reduction might offset the MEM expression. So we let
5278: ;; reload put the address into %edi.
5279:
5280: (define_insn ""
5281: [(set (match_operand:SI 0 "register_operand" "=&c")
5282: (unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "D"))
5283: (match_operand:QI 2 "register_operand" "a")
5284: (match_operand:SI 3 "immediate_operand" "i")] 0))
5285: (clobber (match_dup 1))]
5286: ""
5287: "*
5288: {
5289: rtx xops[2];
5290:
5291: xops[0] = operands[0];
5292: xops[1] = constm1_rtx;
5293: output_asm_insn (\"cld\", operands);
5294: output_asm_insn (AS2 (mov%L0,%1,%0), xops);
5295: return \"repnz\;scas%B2\";
5296: }")
5297:
5298:
5299: ;; Switch the floating-point precision control between single and double.
5300: ;; This doesn't work if the precision control is set to extended.
5301:
5302: (define_insn "fppc_switch"
5303: [(unspec [(match_operand:HI 0 "memory_operand" "m")] 0)]
5304: ""
5305: "fnstcw %0\;xorw $512,%0\;fldcw %0")
5306:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.