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