--- gcc/config/i386/i386.md 2018/04/24 18:10:27 1.1.1.1 +++ gcc/config/i386/i386.md 2018/04/24 18:23:23 1.1.1.3 @@ -1,5 +1,5 @@ -;; GCC machine description for Intel 80386. -;; Copyright (C) 1988 Free Software Foundation, Inc. +;; GCC machine description for Intel X86. +;; Copyright (C) 1988, 1994 Free Software Foundation, Inc. ;; Mostly by William Schelter. ;; This file is part of GNU CC. @@ -45,6 +45,7 @@ ;; 'k' Likewise, print the SImode name of the register. ;; 'h' Print the QImode name for a "high" register, either ah, bh, ch or dh. ;; 'y' Print "st(0)" instead of "st" as a register. +;; 'T' Print the opcode suffix for an 80-bit extended real XFmode float opcode. ;; UNSPEC usage: ;; 0 This is a `scas' operation. The mode of the UNSPEC is always SImode. @@ -156,7 +157,7 @@ if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) output_asm_insn (AS1 (fstp,%y0), operands); - return (char *) output_fp_cc0_set (insn); + return output_fp_cc0_set (insn); }") ;; Don't generate tstsf if generating IEEE code, since the `ftst' opcode @@ -189,7 +190,7 @@ if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) output_asm_insn (AS1 (fstp,%y0), operands); - return (char *) output_fp_cc0_set (insn); + return output_fp_cc0_set (insn); }") ;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode @@ -206,6 +207,39 @@ i386_compare_op0 = operands[0]; DONE; }") + +(define_insn "tstxf_cc" + [(set (cc0) + (match_operand:XF 0 "register_operand" "f")) + (clobber (match_scratch:HI 1 "=a"))] + "TARGET_80387 && ! TARGET_IEEE_FP" + "* +{ + if (! STACK_TOP_P (operands[0])) + abort (); + + output_asm_insn (\"ftst\", operands); + + if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) + output_asm_insn (AS1 (fstp,%y0), operands); + + return output_fp_cc0_set (insn); +}") + +;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode +;; isn't IEEE compliant. + +(define_expand "tstxf" + [(parallel [(set (cc0) + (match_operand:XF 0 "register_operand" "")) + (clobber (match_scratch:HI 1 ""))])] + "TARGET_80387 && ! TARGET_IEEE_FP" + " +{ + i386_compare_gen = gen_tstxf_cc; + i386_compare_op0 = operands[0]; + DONE; +}") ;;- compare instructions. See comments above tstM patterns about ;; expansion of these insns. @@ -310,12 +344,70 @@ (define_insn "" [(set (cc0) (match_operator 2 "VOIDmode_compare_op" + [(match_operand:XF 0 "nonimmediate_operand" "f") + (match_operand:XF 1 "nonimmediate_operand" "f")])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387 + && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "* return output_float_compare (insn, operands);") + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(match_operand:XF 0 "register_operand" "f") + (float:XF + (match_operand:SI 1 "nonimmediate_operand" "rm"))])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);") + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(float:XF + (match_operand:SI 0 "nonimmediate_operand" "rm")) + (match_operand:XF 1 "register_operand" "f")])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);") + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(match_operand:XF 0 "register_operand" "f") + (float_extend:XF + (match_operand:DF 1 "nonimmediate_operand" "fm"))])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);") + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(match_operand:XF 0 "register_operand" "f") + (float_extend:XF + (match_operand:SF 1 "nonimmediate_operand" "fm"))])) + (clobber (match_scratch:HI 3 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);") + +(define_insn "" + [(set (cc0) + (compare:CCFPEQ (match_operand:XF 0 "register_operand" "f") + (match_operand:XF 1 "register_operand" "f"))) + (clobber (match_scratch:HI 2 "=a"))] + "TARGET_80387" + "* return output_float_compare (insn, operands);") + +(define_insn "" + [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" [(match_operand:DF 0 "nonimmediate_operand" "f,fm") (match_operand:DF 1 "nonimmediate_operand" "fm,f")])) (clobber (match_scratch:HI 3 "=a,a"))] "TARGET_80387 && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" - "* return (char *) output_float_compare (insn, operands);") + "* return output_float_compare (insn, operands);") (define_insn "" [(set (cc0) @@ -325,7 +417,7 @@ (match_operand:SI 1 "nonimmediate_operand" "rm"))])) (clobber (match_scratch:HI 3 "=a"))] "TARGET_80387" - "* return (char *) output_float_compare (insn, operands);") + "* return output_float_compare (insn, operands);") (define_insn "" [(set (cc0) @@ -335,7 +427,7 @@ (match_operand:DF 1 "register_operand" "f")])) (clobber (match_scratch:HI 3 "=a"))] "TARGET_80387" - "* return (char *) output_float_compare (insn, operands);") + "* return output_float_compare (insn, operands);") (define_insn "" [(set (cc0) @@ -345,7 +437,7 @@ (match_operand:SF 1 "nonimmediate_operand" "fm"))])) (clobber (match_scratch:HI 3 "=a"))] "TARGET_80387" - "* return (char *) output_float_compare (insn, operands);") + "* return output_float_compare (insn, operands);") (define_insn "" [(set (cc0) @@ -355,7 +447,7 @@ (match_operand:DF 1 "register_operand" "f")])) (clobber (match_scratch:HI 3 "=a"))] "TARGET_80387" - "* return (char *) output_float_compare (insn, operands);") + "* return output_float_compare (insn, operands);") (define_insn "" [(set (cc0) @@ -363,7 +455,7 @@ (match_operand:DF 1 "register_operand" "f"))) (clobber (match_scratch:HI 2 "=a"))] "TARGET_80387" - "* return (char *) output_float_compare (insn, operands);") + "* return output_float_compare (insn, operands);") ;; These two insns will never be generated by combine due to the mode of ;; the COMPARE. @@ -374,7 +466,7 @@ ; (match_operand:SF 1 "register_operand" "f")))) ; (clobber (match_scratch:HI 2 "=a"))] ; "TARGET_80387" -; "* return (char *) output_float_compare (insn, operands);") +; "* return output_float_compare (insn, operands);") ; ;(define_insn "" ; [(set (cc0) @@ -383,7 +475,7 @@ ; (match_operand:DF 1 "register_operand" "f"))) ; (clobber (match_scratch:HI 2 "=a"))] ; "TARGET_80387" -; "* return (char *) output_float_compare (insn, operands);") +; "* return output_float_compare (insn, operands);") (define_insn "cmpsf_cc_1" [(set (cc0) @@ -393,7 +485,7 @@ (clobber (match_scratch:HI 3 "=a,a"))] "TARGET_80387 && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" - "* return (char *) output_float_compare (insn, operands);") + "* return output_float_compare (insn, operands);") (define_insn "" [(set (cc0) @@ -403,7 +495,7 @@ (match_operand:SI 1 "nonimmediate_operand" "rm"))])) (clobber (match_scratch:HI 3 "=a"))] "TARGET_80387" - "* return (char *) output_float_compare (insn, operands);") + "* return output_float_compare (insn, operands);") (define_insn "" [(set (cc0) @@ -413,7 +505,7 @@ (match_operand:SF 1 "register_operand" "f")])) (clobber (match_scratch:HI 3 "=a"))] "TARGET_80387" - "* return (char *) output_float_compare (insn, operands);") + "* return output_float_compare (insn, operands);") (define_insn "" [(set (cc0) @@ -421,7 +513,21 @@ (match_operand:SF 1 "register_operand" "f"))) (clobber (match_scratch:HI 2 "=a"))] "TARGET_80387" - "* return (char *) output_float_compare (insn, operands);") + "* return output_float_compare (insn, operands);") + +(define_expand "cmpxf" + [(set (cc0) + (compare (match_operand:XF 0 "register_operand" "") + (match_operand:XF 1 "nonimmediate_operand" "")))] + "TARGET_80387" + " +{ + i386_compare_gen = gen_cmpxf_cc; + i386_compare_gen_eq = gen_cmpxf_ccfpeq; + i386_compare_op0 = operands[0]; + i386_compare_op1 = operands[1]; + DONE; +}") (define_expand "cmpdf" [(set (cc0) @@ -451,6 +557,26 @@ DONE; }") +(define_expand "cmpxf_cc" + [(parallel [(set (cc0) + (compare (match_operand:XF 0 "register_operand" "") + (match_operand:XF 1 "register_operand" ""))) + (clobber (match_scratch:HI 2 ""))])] + "TARGET_80387" + "") + +(define_expand "cmpxf_ccfpeq" + [(parallel [(set (cc0) + (compare:CCFPEQ (match_operand:XF 0 "register_operand" "") + (match_operand:XF 1 "register_operand" ""))) + (clobber (match_scratch:HI 2 ""))])] + "TARGET_80387" + " +{ + if (! register_operand (operands[1], XFmode)) + operands[1] = copy_to_mode_reg (XFmode, operands[1]); +}") + (define_expand "cmpdf_cc" [(parallel [(set (cc0) (compare (match_operand:DF 0 "register_operand" "") @@ -614,7 +740,7 @@ (define_insn "" [(set (match_operand:SI 0 "push_operand" "=<") (match_operand:SI 1 "general_operand" "g"))] - "! TARGET_486" + "TARGET_386" "push%L0 %1") ;; On a 486, it is faster to move MEM to a REG and then push, rather than @@ -622,8 +748,14 @@ (define_insn "" [(set (match_operand:SI 0 "push_operand" "=<") + (match_operand:SI 1 "nonmemory_operand" "ri"))] + "!TARGET_386 && TARGET_MOVE" + "push%L0 %1") + +(define_insn "" + [(set (match_operand:SI 0 "push_operand" "=<") (match_operand:SI 1 "general_operand" "ri"))] - "TARGET_486" + "!TARGET_386 && !TARGET_MOVE" "push%L0 %1") ;; General case of fullword move. @@ -641,6 +773,15 @@ if (flag_pic && SYMBOLIC_CONST (operands[1])) emit_pic_move (operands, SImode); + + /* Don't generate memory->memory moves, go through a register */ + else if (TARGET_MOVE + && (reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (SImode, operands[1]); + } }") ;; On i486, incl reg is faster than movl $1,reg. @@ -648,7 +789,7 @@ (define_insn "" [(set (match_operand:SI 0 "general_operand" "=g,r") (match_operand:SI 1 "general_operand" "ri,m"))] - "" + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" "* { rtx link; @@ -667,21 +808,52 @@ /* Fastest way to change a 0 to a 1. */ return AS1 (inc%L0,%0); + if (flag_pic && SYMBOLIC_CONST (operands[1])) + return AS2 (lea%L0,%a1,%0); + return AS2 (mov%L0,%1,%0); }") (define_insn "" [(set (match_operand:HI 0 "push_operand" "=<") (match_operand:HI 1 "general_operand" "g"))] - "" + "TARGET_386" + "push%W0 %1") + +(define_insn "" + [(set (match_operand:HI 0 "push_operand" "=<") + (match_operand:HI 1 "nonmemory_operand" "ri"))] + "!TARGET_386 && TARGET_MOVE" + "push%W0 %1") + +(define_insn "" + [(set (match_operand:HI 0 "push_operand" "=<") + (match_operand:HI 1 "general_operand" "ri"))] + "!TARGET_386 && !TARGET_MOVE" "push%W0 %1") ;; On i486, an incl and movl are both faster than incw and movw. -(define_insn "movhi" +(define_expand "movhi" + [(set (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && (reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (HImode, operands[1]); + } +}") + +(define_insn "" [(set (match_operand:HI 0 "general_operand" "=g,r") (match_operand:HI 1 "general_operand" "ri,m"))] - "" + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" "* { rtx link; @@ -711,10 +883,26 @@ return AS2 (mov%W0,%1,%0); }") -(define_insn "movstricthi" +(define_expand "movstricthi" + [(set (strict_low_part (match_operand:HI 0 "general_operand" "")) + (match_operand:HI 1 "general_operand" ""))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && (reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (HImode, operands[1]); + } +}") + +(define_insn "" [(set (strict_low_part (match_operand:HI 0 "general_operand" "+g,r")) (match_operand:HI 1 "general_operand" "ri,m"))] - "" + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" "* { rtx link; @@ -742,8 +930,24 @@ ;; the amount pushed up to a halfword. (define_insn "" [(set (match_operand:QI 0 "push_operand" "=<") - (match_operand:QI 1 "general_operand" "q"))] + (match_operand:QI 1 "immediate_operand" "n"))] "" + "* return AS1 (push%W0,%1);") + +(define_insn "" + [(set (match_operand:QI 0 "push_operand" "=<") + (match_operand:QI 1 "nonimmediate_operand" "q"))] + "!TARGET_MOVE" + "* +{ + operands[1] = gen_rtx (REG, HImode, REGNO (operands[1])); + return AS1 (push%W0,%1); +}") + +(define_insn "" + [(set (match_operand:QI 0 "push_operand" "=<") + (match_operand:QI 1 "register_operand" "q"))] + "TARGET_MOVE" "* { operands[1] = gen_rtx (REG, HImode, REGNO (operands[1])); @@ -755,10 +959,26 @@ ;; ??? Do a recognizer for zero_extract that looks just like this, but reads ;; or writes %ah, %bh, %ch, %dh. -(define_insn "movqi" +(define_expand "movqi" + [(set (match_operand:QI 0 "general_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && (reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (QImode, operands[1]); + } +}") + +(define_insn "" [(set (match_operand:QI 0 "general_operand" "=q,*r,qm") (match_operand:QI 1 "general_operand" "*g,q,qn"))] - "" + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" "* { rtx link; @@ -793,10 +1013,26 @@ ;; If operands[1] is a constant, then an andl/orl sequence would be ;; faster. -(define_insn "movstrictqi" - [(set (strict_low_part (match_operand:QI 0 "general_operand" "+q,qm")) - (match_operand:QI 1 "general_operand" "*g,qn"))] +(define_expand "movstrictqi" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "")) + (match_operand:QI 1 "general_operand" ""))] "" + " +{ + /* Don't generate memory->memory moves, go through a register */ + if (TARGET_MOVE + && (reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) == MEM + && GET_CODE (operands[1]) == MEM) + { + operands[1] = force_reg (QImode, operands[1]); + } +}") + +(define_insn "" + [(set (strict_low_part (match_operand:QI 0 "general_operand" "+qm,q")) + (match_operand:QI 1 "general_operand" "*qn,m"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" "* { rtx link; @@ -815,7 +1051,7 @@ /* Fastest way to change a 0 to a 1. */ return AS1 (inc%B0,%0); - /* If mov%B0 isn't allowed for one of these regs, use mov%W0. */ + /* If mov%B0 isn't allowed for one of these regs, use mov%L0. */ if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1])) { abort (); @@ -825,10 +1061,43 @@ return AS2 (mov%B0,%1,%0); }") -(define_insn "" +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + " +{ + /* Special case memory->memory moves and pushes */ + if (TARGET_MOVE + && (reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) == MEM + && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], SFmode))) + { + rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], SFmode)) + ? gen_movsf_push + : gen_movsf_mem; + + emit_insn ((*genfunc) (operands[0], operands[1])); + DONE; + } + + /* If we are loading a floating point constant that isn't 0 or 1 into a register, + indicate we need the pic register loaded. This could be optimized into stores + of constants if the target eventually moves to memory, but better safe than + sorry. */ + if (flag_pic + && GET_CODE (operands[0]) != MEM + && GET_CODE (operands[1]) == CONST_DOUBLE + && !standard_80387_constant_p (operands[1])) + { + current_function_uses_pic_offset_table = 1; + } +}") + +(define_insn "movsf_push_nomove" [(set (match_operand:SF 0 "push_operand" "=<,<") (match_operand:SF 1 "general_operand" "gF,f"))] - "" + "!TARGET_MOVE" "* { if (STACK_REG_P (operands[1])) @@ -853,14 +1122,61 @@ return AS1 (push%L1,%1); }") -;; Allow MEM-MEM moves before reload. The reload class for such a -;; move will be ALL_REGS. PREFERRED_RELOAD_CLASS will narrow this to -;; GENERAL_REGS. For the purposes of regclass, prefer FLOAT_REGS. +(define_insn "movsf_push" + [(set (match_operand:SF 0 "push_operand" "=<,<,<,<") + (match_operand:SF 1 "general_operand" "rF,f,m,m")) + (clobber (match_scratch:SI 2 "=X,X,r,X"))] + "" + "* +{ + if (STACK_REG_P (operands[1])) + { + rtx xops[3]; + + if (! STACK_TOP_P (operands[1])) + abort (); + + xops[0] = AT_SP (SFmode); + xops[1] = GEN_INT (4); + xops[2] = stack_pointer_rtx; + + output_asm_insn (AS2 (sub%L2,%1,%2), xops); + + if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) + output_asm_insn (AS1 (fstp%S0,%0), xops); + else + output_asm_insn (AS1 (fst%S0,%0), xops); + RET; + } + + else if (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != REG) + return AS1 (push%L1,%1); + + else + { + output_asm_insn (AS2 (mov%L2,%1,%2), operands); + return AS1 (push%L2,%2); + } +}") + +;; Special memory<->memory pattern that combine will recreate from the +;; moves to pseudos. +(define_insn "movsf_mem" + [(set (match_operand:SF 0 "memory_operand" "=m") + (match_operand:SF 1 "memory_operand" "m")) + (clobber (match_scratch:SI 2 "=&r"))] + "" + "* +{ + output_asm_insn (AS2 (mov%L2,%1,%2), operands); + return AS2 (mov%L0,%2,%0); +}") -(define_insn "movsf" +;; For the purposes of regclass, prefer FLOAT_REGS. +(define_insn "movsf_normal" [(set (match_operand:SF 0 "general_operand" "=*rfm,*rf,f,!*rm") (match_operand:SF 1 "general_operand" "*rf,*rfm,fG,fF"))] - "" + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" "* { int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; @@ -902,20 +1218,95 @@ /* Handle other kinds of reads to the 387 */ if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE) - return (char *) output_move_const_single (operands); + return output_move_const_single (operands); if (STACK_TOP_P (operands[0])) return AS1 (fld%z1,%y1); /* Handle all SFmode moves not involving the 387 */ - return (char *) singlemove_string (operands); + return singlemove_string (operands); }") -;;should change to handle the memory operands[1] without doing df push.. -(define_insn "" +(define_insn "swapsf" + [(set (match_operand:SF 0 "register_operand" "f") + (match_operand:SF 1 "register_operand" "f")) + (set (match_dup 1) + (match_dup 0))] + "" + "* +{ + if (STACK_TOP_P (operands[0])) + return AS1 (fxch,%1); + else + return AS1 (fxch,%0); +}") + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + " +{ + /* Special case memory->memory moves and pushes */ + if (TARGET_MOVE + && (reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) == MEM + && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], DFmode))) + { + rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], DFmode)) + ? gen_movdf_push + : gen_movdf_mem; + + emit_insn ((*genfunc) (operands[0], operands[1])); + DONE; + } + + /* If we are loading a floating point constant that isn't 0 or 1 into a register, + indicate we need the pic register loaded. This could be optimized into stores + of constants if the target eventually moves to memory, but better safe than + sorry. */ + if (flag_pic + && GET_CODE (operands[0]) != MEM + && GET_CODE (operands[1]) == CONST_DOUBLE + && !standard_80387_constant_p (operands[1])) + { + current_function_uses_pic_offset_table = 1; + } +}") + +(define_insn "movdf_push_nomove" [(set (match_operand:DF 0 "push_operand" "=<,<") (match_operand:DF 1 "general_operand" "gF,f"))] + "!TARGET_MOVE" + "* +{ + if (STACK_REG_P (operands[1])) + { + rtx xops[3]; + + xops[0] = AT_SP (SFmode); + xops[1] = GEN_INT (8); + xops[2] = stack_pointer_rtx; + + output_asm_insn (AS2 (sub%L2,%1,%2), xops); + + if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) + output_asm_insn (AS1 (fstp%Q0,%0), xops); + else + output_asm_insn (AS1 (fst%Q0,%0), xops); + + RET; + } + else + return output_move_double (operands); +}") + +(define_insn "movdf_push" + [(set (match_operand:DF 0 "push_operand" "=<,<,<,<,<") + (match_operand:DF 1 "general_operand" "rF,f,o,o,o")) + (clobber (match_scratch:SI 2 "=X,X,&r,&r,X")) + (clobber (match_scratch:SI 3 "=X,X,&r,X,X"))] "" "* { @@ -936,8 +1327,76 @@ RET; } + + else if (GET_CODE (operands[1]) != MEM) + return output_move_double (operands); + else - return (char *) output_move_double (operands); + return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 2, 4); +}") + +(define_insn "movdf_mem" + [(set (match_operand:DF 0 "memory_operand" "=o,o") + (match_operand:DF 1 "memory_operand" "o,o")) + (clobber (match_scratch:SI 2 "=&r,&r")) + (clobber (match_scratch:SI 3 "=&r,X"))] + "" + "* return output_move_memory (operands, insn, GET_MODE_SIZE (DFmode), 2, 4);") + +;; For the purposes of regclass, prefer FLOAT_REGS. +(define_insn "movdf_normal" + [(set (match_operand:DF 0 "general_operand" "=f,fm,!*rf,!*rm") + (match_operand:DF 1 "general_operand" "fmG,f,*rfm,*rfF"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + /* First handle a `pop' insn or a `fld %st(0)' */ + + if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1])) + { + if (stack_top_dies) + return AS1 (fstp,%y0); + else + return AS1 (fld,%y0); + } + + /* Handle a transfer between the 387 and a 386 register */ + + if (STACK_TOP_P (operands[0]) && NON_STACK_REG_P (operands[1])) + { + output_op_from_reg (operands[1], AS1 (fld%z0,%y1)); + RET; + } + + if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0])) + { + output_to_reg (operands[0], stack_top_dies); + RET; + } + + /* Handle other kinds of writes from the 387 */ + + if (STACK_TOP_P (operands[1])) + { + if (stack_top_dies) + return AS1 (fstp%z0,%y0); + else + return AS1 (fst%z0,%y0); + } + + /* Handle other kinds of reads to the 387 */ + + if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE) + return output_move_const_single (operands); + + if (STACK_TOP_P (operands[0])) + return AS1 (fld%z1,%y1); + + /* Handle all DFmode moves not involving the 387 */ + + return output_move_double (operands); }") (define_insn "swapdf" @@ -954,14 +1413,109 @@ return AS1 (fxch,%0); }") -;; Allow MEM-MEM moves before reload. The reload class for such a -;; move will be ALL_REGS. PREFERRED_RELOAD_CLASS will narrow this to -;; GENERAL_REGS. For the purposes of regclass, prefer FLOAT_REGS. - -(define_insn "movdf" - [(set (match_operand:DF 0 "general_operand" "=*rfm,*rf,f,!*rm") - (match_operand:DF 1 "general_operand" "*rf,*rfm,fG,fF"))] +(define_expand "movxf" + [(set (match_operand:XF 0 "general_operand" "") + (match_operand:XF 1 "general_operand" ""))] + "" + " +{ + /* Special case memory->memory moves and pushes */ + if (TARGET_MOVE + && (reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) == MEM + && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], XFmode))) + { + rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], XFmode)) + ? gen_movxf_push + : gen_movxf_mem; + + emit_insn ((*genfunc) (operands[0], operands[1])); + DONE; + } + + /* If we are loading a floating point constant that isn't 0 or 1 into a register, + indicate we need the pic register loaded. This could be optimized into stores + of constants if the target eventually moves to memory, but better safe than + sorry. */ + if (flag_pic + && GET_CODE (operands[0]) != MEM + && GET_CODE (operands[1]) == CONST_DOUBLE + && !standard_80387_constant_p (operands[1])) + { + current_function_uses_pic_offset_table = 1; + } +}") + + +(define_insn "movxf_push_nomove" + [(set (match_operand:XF 0 "push_operand" "=<,<") + (match_operand:XF 1 "general_operand" "gF,f"))] + "!TARGET_MOVE" + "* +{ + if (STACK_REG_P (operands[1])) + { + rtx xops[3]; + + xops[0] = AT_SP (SFmode); + xops[1] = GEN_INT (12); + xops[2] = stack_pointer_rtx; + + output_asm_insn (AS2 (sub%L2,%1,%2), xops); + output_asm_insn (AS1 (fstp%T0,%0), xops); + if (! find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) + output_asm_insn (AS1 (fld%T0,%0), xops); + + RET; + } + else + return output_move_double (operands); + }") + +(define_insn "movxf_push" + [(set (match_operand:XF 0 "push_operand" "=<,<,<,<,<") + (match_operand:XF 1 "general_operand" "rF,f,o,o,o")) + (clobber (match_scratch:SI 2 "=X,X,&r,&r,X")) + (clobber (match_scratch:SI 3 "=X,X,&r,X,X"))] + "" + "* +{ + if (STACK_REG_P (operands[1])) + { + rtx xops[3]; + + xops[0] = AT_SP (SFmode); + xops[1] = GEN_INT (12); + xops[2] = stack_pointer_rtx; + + output_asm_insn (AS2 (sub%L2,%1,%2), xops); + output_asm_insn (AS1 (fstp%T0,%0), xops); + if (! find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) + output_asm_insn (AS1 (fld%T0,%0), xops); + + RET; + } + + else if (GET_CODE (operands[1]) != MEM + || GET_CODE (operands[2]) != REG) + return output_move_double (operands); + + else + return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 2, 4); +}") + +(define_insn "movxf_mem" + [(set (match_operand:XF 0 "memory_operand" "=o,o") + (match_operand:XF 1 "memory_operand" "o,o")) + (clobber (match_scratch:SI 2 "=&r,&r")) + (clobber (match_scratch:SI 3 "=&r,X"))] "" + "* return output_move_memory (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);") + +(define_insn "movxf_normal" + [(set (match_operand:XF 0 "general_operand" "=f,fm,!*rf,!*rm") + (match_operand:XF 1 "general_operand" "fmG,f,*rfm,*rfF"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" "* { int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; @@ -994,42 +1548,71 @@ if (STACK_TOP_P (operands[1])) { - if (stack_top_dies) - return AS1 (fstp%z0,%y0); - else - return AS1 (fst%z0,%y0); + output_asm_insn (AS1 (fstp%z0,%y0), operands); + if (! stack_top_dies) + return AS1 (fld%z0,%y0); + + RET; } /* Handle other kinds of reads to the 387 */ if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE) - return (char *) output_move_const_single (operands); + return output_move_const_single (operands); if (STACK_TOP_P (operands[0])) - return AS1 (fld%z1,%y1); + return AS1 (fld%z1,%y1); - /* Handle all DFmode moves not involving the 387 */ + /* Handle all XFmode moves not involving the 387 */ - return (char *) output_move_double (operands); + return output_move_double (operands); +}") + +(define_insn "swapxf" + [(set (match_operand:XF 0 "register_operand" "f") + (match_operand:XF 1 "register_operand" "f")) + (set (match_dup 1) + (match_dup 0))] + "" + "* +{ + if (STACK_TOP_P (operands[0])) + return AS1 (fxch,%1); + else + return AS1 (fxch,%0); }") (define_insn "" - [(set (match_operand:DI 0 "push_operand" "=<") - (match_operand:DI 1 "general_operand" "roiF"))] + [(set (match_operand:DI 0 "push_operand" "=<,<,<,<") + (match_operand:DI 1 "general_operand" "riF,o,o,o")) + (clobber (match_scratch:SI 2 "=X,&r,&r,X")) + (clobber (match_scratch:SI 3 "=X,&r,X,X"))] "" "* { - return (char *) output_move_double (operands); + if (GET_CODE (operands[1]) != MEM) + return output_move_double (operands); + + else + return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode), 2, 4); }") (define_insn "movdi" - [(set (match_operand:DI 0 "general_operand" "=r,rm") - (match_operand:DI 1 "general_operand" "m,riF"))] + [(set (match_operand:DI 0 "general_operand" "=o,o,r,rm") + (match_operand:DI 1 "general_operand" "o,o,m,riF")) + (clobber (match_scratch:SI 2 "=&r,&r,X,X")) + (clobber (match_scratch:SI 3 "=&r,X,X,X"))] "" "* { - return (char *) output_move_double (operands); + rtx low[2], high[2], xop[6]; + + if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + return output_move_double (operands); + else + return output_move_memory (operands, insn, GET_MODE_SIZE (DImode), 2, 4); }") + ;;- conversion instructions ;;- NONE @@ -1044,7 +1627,7 @@ "" "* { - if ((TARGET_486 || REGNO (operands[0]) == 0) + if ((!TARGET_386 || REGNO (operands[0]) == 0) && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1])) { rtx xops[2]; @@ -1068,7 +1651,7 @@ "" "* { - if ((TARGET_486 || REGNO (operands[0]) == 0) + if ((!TARGET_386 || REGNO (operands[0]) == 0) && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1])) { rtx xops[2]; @@ -1092,7 +1675,7 @@ "" "* { - if ((TARGET_486 || REGNO (operands[0]) == 0) + if ((!TARGET_386 || REGNO (operands[0]) == 0) && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1])) { rtx xops[2]; @@ -1241,6 +1824,76 @@ abort (); }") +(define_insn "extenddfxf2" + [(set (match_operand:XF 0 "general_operand" "=fm,f,f,!*r") + (float_extend:XF + (match_operand:DF 1 "general_operand" "f,fm,!*r,f")))] + "TARGET_80387" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + if (NON_STACK_REG_P (operands[1])) + { + output_op_from_reg (operands[1], AS1 (fld%z0,%y1)); + RET; + } + + if (NON_STACK_REG_P (operands[0])) + { + output_to_reg (operands[0], stack_top_dies); + RET; + } + + if (STACK_TOP_P (operands[0])) + return AS1 (fld%z1,%y1); + + if (GET_CODE (operands[0]) == MEM) + { + output_asm_insn (AS1 (fstp%z0,%y0), operands); + if (! stack_top_dies) + return AS1 (fld%z0,%y0); + RET; + } + + abort (); +}") + +(define_insn "extendsfxf2" + [(set (match_operand:XF 0 "general_operand" "=fm,f,f,!*r") + (float_extend:XF + (match_operand:SF 1 "general_operand" "f,fm,!*r,f")))] + "TARGET_80387" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + if (NON_STACK_REG_P (operands[1])) + { + output_op_from_reg (operands[1], AS1 (fld%z0,%y1)); + RET; + } + + if (NON_STACK_REG_P (operands[0])) + { + output_to_reg (operands[0], stack_top_dies); + RET; + } + + if (STACK_TOP_P (operands[0])) + return AS1 (fld%z1,%y1); + + if (GET_CODE (operands[0]) == MEM) + { + output_asm_insn (AS1 (fstp%z0,%y0), operands); + if (! stack_top_dies) + return AS1 (fld%z0,%y0); + RET; + } + + abort (); +}") + (define_expand "truncdfsf2" [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "") (float_truncate:SF @@ -1282,6 +1935,73 @@ else abort (); }") + +(define_insn "truncxfsf2" + [(set (match_operand:SF 0 "general_operand" "=m,!*r") + (float_truncate:SF + (match_operand:XF 1 "register_operand" "f,f")))] + "TARGET_80387" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + if (NON_STACK_REG_P (operands[0])) + { + if (stack_top_dies == 0) + { + output_asm_insn (AS1 (fld,%y1), operands); + stack_top_dies = 1; + } + output_to_reg (operands[0], stack_top_dies); + RET; + } + else if (GET_CODE (operands[0]) == MEM) + { + if (stack_top_dies) + return AS1 (fstp%z0,%0); + else + { + output_asm_insn (AS1 (fld,%y1), operands); + return AS1 (fstp%z0,%0); + } + } + else + abort (); +}") + +(define_insn "truncxfdf2" + [(set (match_operand:DF 0 "general_operand" "=m,!*r") + (float_truncate:DF + (match_operand:XF 1 "register_operand" "f,f")))] + "TARGET_80387" + "* +{ + int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0; + + if (NON_STACK_REG_P (operands[0])) + { + if (stack_top_dies == 0) + { + output_asm_insn (AS1 (fld,%y1), operands); + stack_top_dies = 1; + } + output_to_reg (operands[0], stack_top_dies); + RET; + } + else if (GET_CODE (operands[0]) == MEM) + { + if (stack_top_dies) + return AS1 (fstp%z0,%0); + else + { + output_asm_insn (AS1 (fld,%y1), operands); + return AS1 (fstp%z0,%0); + } + } + else + abort (); +}") + ;; The 387 requires that the stack top dies after converting to DImode. @@ -1289,6 +2009,27 @@ ;; doing a signed conversion to DImode, and then taking just the low ;; part. +(define_expand "fixuns_truncxfsi2" + [(set (match_dup 4) + (match_operand:XF 1 "register_operand" "")) + (parallel [(set (match_dup 2) + (fix:DI (fix:XF (match_dup 4)))) + (clobber (match_dup 4)) + (clobber (match_dup 5)) + (clobber (match_dup 6)) + (clobber (match_scratch:SI 7 ""))]) + (set (match_operand:SI 0 "general_operand" "") + (match_dup 3))] + "TARGET_80387" + " +{ + operands[2] = gen_reg_rtx (DImode); + operands[3] = gen_lowpart (SImode, operands[2]); + operands[4] = gen_reg_rtx (XFmode); + operands[5] = (rtx) assign_386_stack_local (SImode, 0); + operands[6] = (rtx) assign_386_stack_local (SImode, 1); +}") + (define_expand "fixuns_truncdfsi2" [(set (match_dup 4) (match_operand:DF 1 "register_operand" "")) @@ -1333,6 +2074,24 @@ ;; Signed conversion to DImode. +(define_expand "fix_truncxfdi2" + [(set (match_dup 2) + (match_operand:XF 1 "register_operand" "")) + (parallel [(set (match_operand:DI 0 "general_operand" "") + (fix:DI (fix:XF (match_dup 2)))) + (clobber (match_dup 2)) + (clobber (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_scratch:SI 5 ""))])] + "TARGET_80387" + " +{ + operands[1] = copy_to_mode_reg (XFmode, operands[1]); + operands[2] = gen_reg_rtx (XFmode); + operands[3] = (rtx) assign_386_stack_local (SImode, 0); + operands[4] = (rtx) assign_386_stack_local (SImode, 1); +}") + (define_expand "fix_truncdfdi2" [(set (match_dup 2) (match_operand:DF 1 "register_operand" "")) @@ -1373,13 +2132,23 @@ (define_insn "" [(set (match_operand:DI 0 "general_operand" "=rm") + (fix:DI (fix:XF (match_operand:XF 1 "register_operand" "f")))) + (clobber (match_dup 1)) + (clobber (match_operand:SI 2 "memory_operand" "m")) + (clobber (match_operand:SI 3 "memory_operand" "m")) + (clobber (match_scratch:SI 4 "=&q"))] + "TARGET_80387" + "* return output_fix_trunc (insn, operands);") + +(define_insn "" + [(set (match_operand:DI 0 "general_operand" "=rm") (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f")))) (clobber (match_dup 1)) (clobber (match_operand:SI 2 "memory_operand" "m")) (clobber (match_operand:SI 3 "memory_operand" "m")) (clobber (match_scratch:SI 4 "=&q"))] "TARGET_80387" - "* return (char *) output_fix_trunc (insn, operands);") + "* return output_fix_trunc (insn, operands);") (define_insn "" [(set (match_operand:DI 0 "general_operand" "=rm") @@ -1389,10 +2158,24 @@ (clobber (match_operand:SI 3 "memory_operand" "m")) (clobber (match_scratch:SI 4 "=&q"))] "TARGET_80387" - "* return (char *) output_fix_trunc (insn, operands);") + "* return output_fix_trunc (insn, operands);") ;; Signed MODE_FLOAT conversion to SImode. +(define_expand "fix_truncxfsi2" + [(parallel [(set (match_operand:SI 0 "general_operand" "") + (fix:SI + (fix:XF (match_operand:XF 1 "register_operand" "")))) + (clobber (match_dup 2)) + (clobber (match_dup 3)) + (clobber (match_scratch:SI 4 ""))])] + "TARGET_80387" + " +{ + operands[2] = (rtx) assign_386_stack_local (SImode, 0); + operands[3] = (rtx) assign_386_stack_local (SImode, 1); +}") + (define_expand "fix_truncdfsi2" [(parallel [(set (match_operand:SI 0 "general_operand" "") (fix:SI @@ -1423,12 +2206,21 @@ (define_insn "" [(set (match_operand:SI 0 "general_operand" "=rm") + (fix:SI (fix:XF (match_operand:XF 1 "register_operand" "f")))) + (clobber (match_operand:SI 2 "memory_operand" "m")) + (clobber (match_operand:SI 3 "memory_operand" "m")) + (clobber (match_scratch:SI 4 "=&q"))] + "TARGET_80387" + "* return output_fix_trunc (insn, operands);") + +(define_insn "" + [(set (match_operand:SI 0 "general_operand" "=rm") (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f")))) (clobber (match_operand:SI 2 "memory_operand" "m")) (clobber (match_operand:SI 3 "memory_operand" "m")) (clobber (match_scratch:SI 4 "=&q"))] "TARGET_80387" - "* return (char *) output_fix_trunc (insn, operands);") + "* return output_fix_trunc (insn, operands);") (define_insn "" [(set (match_operand:SI 0 "general_operand" "=rm") @@ -1437,7 +2229,7 @@ (clobber (match_operand:SI 3 "memory_operand" "m")) (clobber (match_scratch:SI 4 "=&q"))] "TARGET_80387" - "* return (char *) output_fix_trunc (insn, operands);") + "* return output_fix_trunc (insn, operands);") ;; Conversion between fixed point and floating point. ;; The actual pattern that matches these is at the end of this file. @@ -1468,9 +2260,38 @@ "TARGET_80387" "") +(define_expand "floatsixf2" + [(set (match_operand:XF 0 "register_operand" "") + (float:XF (match_operand:SI 1 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + +(define_expand "floatdixf2" + [(set (match_operand:XF 0 "register_operand" "") + (float:XF (match_operand:DI 1 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + ;; This will convert from SImode or DImode to MODE_FLOAT. (define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (float:XF (match_operand:DI 1 "general_operand" "rm")))] + "TARGET_80387" + "* +{ + if (NON_STACK_REG_P (operands[1])) + { + output_op_from_reg (operands[1], AS1 (fild%z0,%1)); + RET; + } + else if (GET_CODE (operands[1]) == MEM) + return AS1 (fild%z1,%1); + else + abort (); +}") + +(define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (float:DF (match_operand:DI 1 "nonimmediate_operand" "rm")))] "TARGET_80387" @@ -1522,6 +2343,23 @@ }") (define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (float:XF (match_operand:SI 1 "general_operand" "m,!*r")))] + "TARGET_80387" + "* +{ + if (NON_STACK_REG_P (operands[1])) + { + output_op_from_reg (operands[1], AS1 (fild%z0,%1)); + RET; + } + else if (GET_CODE (operands[1]) == MEM) + return AS1 (fild%z1,%1); + else + abort (); +}") + +(define_insn "" [(set (match_operand:SF 0 "register_operand" "=f") (float:SF (match_operand:SI 1 "nonimmediate_operand" "rm")))] "TARGET_80387" @@ -1541,25 +2379,75 @@ ;;- add instructions (define_insn "adddi3" - [(set (match_operand:DI 0 "general_operand" "=&r,ro") - (plus:DI (match_operand:DI 1 "general_operand" "%0,0") - (match_operand:DI 2 "general_operand" "o,riF")))] + [(set (match_operand:DI 0 "general_operand" "=&r,ro,o,&r,ro,o,&r,o,o,o") + (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,o,riF,o,or,riF,riF,o") + (match_operand:DI 2 "general_operand" "o,riF,o,0,0,0,oriF,riF,o,o"))) + (clobber (match_scratch:SI 3 "=X,X,&r,X,X,&r,X,X,&r,&r"))] "" "* { - rtx low[3], high[3]; + rtx low[3], high[3], xops[7], temp; CC_STATUS_INIT; + if (rtx_equal_p (operands[0], operands[2])) + { + temp = operands[1]; + operands[1] = operands[2]; + operands[2] = temp; + } + split_di (operands, 3, low, high); + if (!rtx_equal_p (operands[0], operands[1])) + { + xops[0] = high[0]; + xops[1] = low[0]; + xops[2] = high[1]; + xops[3] = low[1]; + + if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + { + output_asm_insn (AS2 (mov%L1,%3,%1), xops); + output_asm_insn (AS2 (mov%L0,%2,%0), xops); + } + else + { + xops[4] = high[2]; + xops[5] = low[2]; + xops[6] = operands[3]; + output_asm_insn (AS2 (mov%L6,%3,%6), xops); + output_asm_insn (AS2 (add%L6,%5,%6), xops); + output_asm_insn (AS2 (mov%L1,%6,%1), xops); + output_asm_insn (AS2 (mov%L6,%2,%6), xops); + output_asm_insn (AS2 (adc%L6,%4,%6), xops); + output_asm_insn (AS2 (mov%L0,%6,%0), xops); + RET; + } + } + + if (GET_CODE (operands[3]) == REG && GET_CODE (operands[2]) != REG) + { + xops[0] = high[0]; + xops[1] = low[0]; + xops[2] = high[2]; + xops[3] = low[2]; + xops[4] = operands[3]; + + output_asm_insn (AS2 (mov%L4,%3,%4), xops); + output_asm_insn (AS2 (add%L1,%4,%1), xops); + output_asm_insn (AS2 (mov%L4,%2,%4), xops); + output_asm_insn (AS2 (adc%L0,%4,%0), xops); + } - if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0) + else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0) { output_asm_insn (AS2 (add%L0,%2,%0), low); output_asm_insn (AS2 (adc%L0,%2,%0), high); } + else output_asm_insn (AS2 (add%L0,%2,%0), high); + RET; }") @@ -1578,23 +2466,20 @@ if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2])) return AS2 (add%L0,%1,%0); - if (! TARGET_486 || ! REG_P (operands[2])) - { - CC_STATUS_INIT; + if (operands[2] == stack_pointer_rtx) + { + rtx temp; - if (operands[2] == stack_pointer_rtx) - { - rtx temp; + temp = operands[1]; + operands[1] = operands[2]; + operands[2] = temp; + } - temp = operands[1]; - operands[1] = operands[2]; - operands[2] = temp; - } - if (operands[2] != stack_pointer_rtx) - { - operands[1] = SET_SRC (PATTERN (insn)); - return AS2 (lea%L0,%a1,%0); - } + if (operands[2] != stack_pointer_rtx) + { + CC_STATUS_INIT; + operands[1] = SET_SRC (PATTERN (insn)); + return AS2 (lea%L0,%a1,%0); } output_asm_insn (AS2 (mov%L0,%1,%0), operands); @@ -1620,10 +2505,29 @@ "" "* { + /* ??? what about offsettable memory references? */ + if (QI_REG_P (operands[0]) + && GET_CODE (operands[2]) == CONST_INT + && (INTVAL (operands[2]) & 0xff) == 0) + { + int byteval = (INTVAL (operands[2]) >> 8) & 0xff; + CC_STATUS_INIT; + + if (byteval == 1) + return AS1 (inc%B0,%h0); + else if (byteval == 255) + return AS1 (dec%B0,%h0); + + operands[2] = GEN_INT (byteval); + return AS2 (add%B0,%2,%h0); + } + if (operands[2] == const1_rtx) return AS1 (inc%W0,%0); - if (operands[2] == constm1_rtx) + if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 65535)) return AS1 (dec%W0,%0); return AS2 (add%W0,%2,%0); @@ -1639,7 +2543,9 @@ if (operands[2] == const1_rtx) return AS1 (inc%B0,%0); - if (operands[2] == constm1_rtx) + if (operands[2] == constm1_rtx + || (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 255)) return AS1 (dec%B0,%0); return AS2 (add%B0,%2,%0); @@ -1672,7 +2578,7 @@ ;; addsi3 is faster, so put this after. -(define_insn "" +(define_insn "movsi_lea" [(set (match_operand:SI 0 "register_operand" "=r") (match_operand:QI 1 "address_operand" "p"))] "" @@ -1700,6 +2606,13 @@ ;; The patterns that match these are at the end of this file. +(define_expand "addxf3" + [(set (match_operand:XF 0 "register_operand" "") + (plus:XF (match_operand:XF 1 "nonimmediate_operand" "") + (match_operand:XF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + (define_expand "adddf3" [(set (match_operand:DF 0 "register_operand" "") (plus:DF (match_operand:DF 1 "nonimmediate_operand" "") @@ -1717,23 +2630,66 @@ ;;- subtract instructions (define_insn "subdi3" - [(set (match_operand:DI 0 "general_operand" "=&r,ro") - (minus:DI (match_operand:DI 1 "general_operand" "0,0") - (match_operand:DI 2 "general_operand" "o,riF")))] + [(set (match_operand:DI 0 "general_operand" "=&r,ro,&r,o,o") + (minus:DI (match_operand:DI 1 "general_operand" "0,0,roiF,riF,o") + (match_operand:DI 2 "general_operand" "o,riF,roiF,riF,o"))) + (clobber (match_scratch:SI 3 "=X,X,X,X,&r"))] "" "* { - rtx low[3], high[3]; + rtx low[3], high[3], xops[7]; CC_STATUS_INIT; split_di (operands, 3, low, high); - if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0) + if (!rtx_equal_p (operands[0], operands[1])) + { + xops[0] = high[0]; + xops[1] = low[0]; + xops[2] = high[1]; + xops[3] = low[1]; + + if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) + { + output_asm_insn (AS2 (mov%L1,%3,%1), xops); + output_asm_insn (AS2 (mov%L0,%2,%0), xops); + } + else + { + xops[4] = high[2]; + xops[5] = low[2]; + xops[6] = operands[3]; + output_asm_insn (AS2 (mov%L6,%3,%6), xops); + output_asm_insn (AS2 (sub%L6,%5,%6), xops); + output_asm_insn (AS2 (mov%L1,%6,%1), xops); + output_asm_insn (AS2 (mov%L6,%2,%6), xops); + output_asm_insn (AS2 (sbb%L6,%4,%6), xops); + output_asm_insn (AS2 (mov%L0,%6,%0), xops); + RET; + } + } + + if (GET_CODE (operands[3]) == REG) + { + xops[0] = high[0]; + xops[1] = low[0]; + xops[2] = high[2]; + xops[3] = low[2]; + xops[4] = operands[3]; + + output_asm_insn (AS2 (mov%L4,%3,%4), xops); + output_asm_insn (AS2 (sub%L1,%4,%1), xops); + output_asm_insn (AS2 (mov%L4,%2,%4), xops); + output_asm_insn (AS2 (sbb%L0,%4,%0), xops); + } + + else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0) { output_asm_insn (AS2 (sub%L0,%2,%0), low); output_asm_insn (AS2 (sbb%L0,%2,%0), high); } + else output_asm_insn (AS2 (sub%L0,%2,%0), high); @@ -1763,6 +2719,13 @@ ;; The patterns that match these are at the end of this file. +(define_expand "subxf3" + [(set (match_operand:XF 0 "register_operand" "") + (minus:XF (match_operand:XF 1 "nonimmediate_operand" "") + (match_operand:XF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + (define_expand "subdf3" [(set (match_operand:DF 0 "register_operand" "") (minus:DF (match_operand:DF 1 "nonimmediate_operand" "") @@ -1788,14 +2751,14 @@ (define_insn "" [(set (match_operand:HI 0 "general_operand" "=r") - (mult:SI (match_operand:HI 1 "general_operand" "%0") + (mult:HI (match_operand:HI 1 "general_operand" "%0") (match_operand:HI 2 "general_operand" "r")))] "GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80" "* return AS2 (imul%W0,%2,%0);") (define_insn "mulhi3" [(set (match_operand:HI 0 "general_operand" "=r,r") - (mult:SI (match_operand:HI 1 "general_operand" "%0,rm") + (mult:HI (match_operand:HI 1 "general_operand" "%0,rm") (match_operand:HI 2 "general_operand" "g,i")))] "" "* @@ -1830,17 +2793,61 @@ return AS3 (imul%L0,%2,%1,%0); }") -(define_insn "" +(define_insn "umulqihi3" [(set (match_operand:HI 0 "general_operand" "=a") - (mult:SI (zero_extend:HI - (match_operand:QI 1 "nonimmediate_operand" "%0")) - (zero_extend:HI - (match_operand:QI 2 "nonimmediate_operand" "qm"))))] + (mult:HI (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0")) + (zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))] "" "mul%B0 %2") +(define_insn "mulqihi3" + [(set (match_operand:HI 0 "general_operand" "=a") + (mult:HI (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0")) + (sign_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))] + "" + "imul%B0 %2") + +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "register_operand" "=A") + (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) + (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))] + "TARGET_WIDE_MULTIPLY" + "mul%L0 %2") + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "register_operand" "=A") + (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0")) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))] + "TARGET_WIDE_MULTIPLY" + "imul%L0 %2") + +(define_insn "umulsi3_highpart" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%a")) + (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=a"))] + "TARGET_WIDE_MULTIPLY" + "mul%L0 %2") + +(define_insn "smulsi3_highpart" + [(set (match_operand:SI 0 "register_operand" "=d") + (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%a")) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=a"))] + "TARGET_WIDE_MULTIPLY" + "imul%L0 %2") + ;; The patterns that match these are at the end of this file. +(define_expand "mulxf3" + [(set (match_operand:XF 0 "register_operand" "") + (mult:XF (match_operand:XF 1 "nonimmediate_operand" "") + (match_operand:XF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + (define_expand "muldf3" [(set (match_operand:DF 0 "register_operand" "") (mult:DF (match_operand:DF 1 "nonimmediate_operand" "") @@ -1873,6 +2880,13 @@ ;; The patterns that match these are at the end of this file. +(define_expand "divxf3" + [(set (match_operand:XF 0 "register_operand" "") + (div:XF (match_operand:XF 1 "nonimmediate_operand" "") + (match_operand:XF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + (define_expand "divdf3" [(set (match_operand:DF 0 "register_operand" "") (div:DF (match_operand:DF 1 "nonimmediate_operand" "") @@ -1987,7 +3001,7 @@ if (INTVAL (operands[2]) == 0xffff && REG_P (operands[0]) && (! REG_P (operands[1]) || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0) - && (! TARGET_486 || ! rtx_equal_p (operands[0], operands[1]))) + && (TARGET_386 || ! rtx_equal_p (operands[0], operands[1]))) { /* ??? tege: Should forget CC_STATUS only if we clobber a remembered operand. Fix that later. */ @@ -2003,7 +3017,7 @@ && !(REG_P (operands[1]) && NON_QI_REG_P (operands[1])) && (! REG_P (operands[1]) || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0) - && (! TARGET_486 || ! rtx_equal_p (operands[0], operands[1]))) + && (TARGET_386 || ! rtx_equal_p (operands[0], operands[1]))) { /* ??? tege: Should forget CC_STATUS only if we clobber a remembered operand. Fix that later. */ @@ -2363,6 +3377,18 @@ (neg:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))] "TARGET_80387" "fchs") + +(define_insn "negxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (neg:XF (match_operand:XF 1 "general_operand" "0")))] + "TARGET_80387" + "fchs") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (neg:XF (float_extend:XF (match_operand:DF 1 "general_operand" "0"))))] + "TARGET_80387" + "fchs") ;; Absolute value instructions @@ -2384,61 +3410,105 @@ "TARGET_80387" "fabs") +(define_insn "absxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (abs:XF (match_operand:XF 1 "general_operand" "0")))] + "TARGET_80387" + "fabs") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (abs:XF (float_extend:XF (match_operand:DF 1 "general_operand" "0"))))] + "TARGET_80387" + "fabs") + (define_insn "sqrtsf2" [(set (match_operand:SF 0 "register_operand" "=f") (sqrt:SF (match_operand:SF 1 "general_operand" "0")))] - "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " "fsqrt") (define_insn "sqrtdf2" [(set (match_operand:DF 0 "register_operand" "=f") (sqrt:DF (match_operand:DF 1 "general_operand" "0")))] - "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " "fsqrt") (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (sqrt:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))] - "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " + "fsqrt") + +(define_insn "sqrtxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (sqrt:XF (match_operand:XF 1 "general_operand" "0")))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " + "fsqrt") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (sqrt:XF (float_extend:XF + (match_operand:DF 1 "general_operand" "0"))))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " + "fsqrt") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (sqrt:XF (float_extend:XF + (match_operand:SF 1 "general_operand" "0"))))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " "fsqrt") (define_insn "sindf2" [(set (match_operand:DF 0 "register_operand" "=f") (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))] - "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " "fsin") (define_insn "sinsf2" [(set (match_operand:SF 0 "register_operand" "=f") (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))] - "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " "fsin") (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (unspec:DF [(float_extend:DF (match_operand:SF 1 "register_operand" "0"))] 1))] - "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " "fsin") (define_insn "cosdf2" [(set (match_operand:DF 0 "register_operand" "=f") (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))] - "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " "fcos") (define_insn "cossf2" [(set (match_operand:SF 0 "register_operand" "=f") (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))] - "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " "fcos") (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (unspec:DF [(float_extend:DF (match_operand:SF 1 "register_operand" "0"))] 2))] - "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && (TARGET_IEEE_FP || flag_fast_math) " "fcos") ;;- one complement instructions @@ -2590,7 +3660,7 @@ { if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1])) { - if (TARGET_486 && INTVAL (operands[2]) == 1) + if (!TARGET_386 && INTVAL (operands[2]) == 1) { output_asm_insn (AS2 (mov%L0,%1,%0), operands); return AS2 (add%L0,%1,%0); @@ -3091,7 +4161,7 @@ (const_int 1) (match_operand:SI 2 "general_operand" "r")) (match_operand:SI 3 "const_int_operand" "n"))] - "! TARGET_486 && GET_CODE (operands[2]) != CONST_INT" + "TARGET_386 && GET_CODE (operands[2]) != CONST_INT" "* { CC_STATUS_INIT; @@ -3109,7 +4179,7 @@ (xor:SI (ashift:SI (const_int 1) (match_operand:SI 1 "general_operand" "r")) (match_operand:SI 2 "general_operand" "0")))] - "! TARGET_486 && GET_CODE (operands[1]) != CONST_INT" + "TARGET_386 && GET_CODE (operands[1]) != CONST_INT" "* { CC_STATUS_INIT; @@ -3122,7 +4192,7 @@ (xor:SI (match_operand:SI 1 "general_operand" "0") (ashift:SI (const_int 1) (match_operand:SI 2 "general_operand" "r"))))] - "! TARGET_486 && GET_CODE (operands[2]) != CONST_INT" + "TARGET_386 && GET_CODE (operands[2]) != CONST_INT" "* { CC_STATUS_INIT; @@ -4140,126 +5210,42 @@ "!HALF_PIC_P ()" "call %P1") +;; Call subroutine returning any type. + (define_expand "untyped_call" - [(parallel [(call (match_operand:QI 0 "indirect_operand" "") + [(parallel [(call (match_operand 0 "" "") (const_int 0)) - (match_operand:BLK 1 "memory_operand" "") + (match_operand 1 "" "") (match_operand 2 "" "")])] "" " { - rtx addr; - - if (flag_pic) - current_function_uses_pic_offset_table = 1; - - /* With half-pic, force the address into a register. */ - addr = XEXP (operands[0], 0); - if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr)) - XEXP (operands[0], 0) = force_reg (Pmode, addr); - - operands[1] = change_address (operands[1], DImode, XEXP (operands[1], 0)); - if (! expander_call_insn_operand (operands[1], QImode)) - operands[1] - = change_address (operands[1], VOIDmode, - copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); -}") + int i; -(define_insn "" - [(call (match_operand:QI 0 "call_insn_operand" "m") - (const_int 0)) - (match_operand:DI 1 "memory_operand" "o") - (match_operand 2 "" "")] - "" - "* -{ - rtx addr = operands[1]; + emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx)); - if (GET_CODE (operands[0]) == MEM - && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) + for (i = 0; i < XVECLEN (operands[2], 0); i++) { - operands[0] = XEXP (operands[0], 0); - output_asm_insn (AS1 (call,%*%0), operands); + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); } - else - output_asm_insn (AS1 (call,%P0), operands); - - operands[2] = gen_rtx (REG, SImode, 0); - output_asm_insn (AS2 (mov%L2,%2,%1), operands); - - operands[2] = gen_rtx (REG, SImode, 1); - operands[1] = adj_offsettable_operand (addr, 4); - output_asm_insn (AS2 (mov%L2,%2,%1), operands); - - operands[1] = adj_offsettable_operand (addr, 8); - return AS1 (fnsave,%1); -}") - -(define_insn "" - [(call (mem:QI (match_operand:SI 0 "symbolic_operand" "")) - (const_int 0)) - (match_operand:DI 1 "memory_operand" "o") - (match_operand 2 "" "")] - "!HALF_PIC_P ()" - "* -{ - rtx addr = operands[1]; - output_asm_insn (AS1 (call,%P0), operands); - - operands[2] = gen_rtx (REG, SImode, 0); - output_asm_insn (AS2 (mov%L2,%2,%1), operands); - - operands[2] = gen_rtx (REG, SImode, 1); - operands[1] = adj_offsettable_operand (addr, 4); - output_asm_insn (AS2 (mov%L2,%2,%1), operands); - - operands[1] = adj_offsettable_operand (addr, 8); - return AS1 (fnsave,%1); -}") - -;; We use fnsave and frstor to save and restore the floating point result. -;; These are expensive instructions and require a large space to save the -;; FPU state. An more complicated alternative is to use fnstenv to store -;; the FPU environment and test whether the stack top is valid. Store the -;; result of the test, and if it is valid, pop and save the value. The -;; untyped_return would check the test and optionally push the saved value. - -(define_expand "untyped_return" - [(match_operand:BLK 0 "memory_operand" "") - (match_operand 1 "" "")] - "" - " -{ - rtx valreg1 = gen_rtx (REG, SImode, 0); - rtx valreg2 = gen_rtx (REG, SImode, 1); - rtx result = operands[0]; - - /* Restore the FPU state. */ - emit_insn (gen_update_return (change_address (result, SImode, - plus_constant (XEXP (result, 0), - 8)))); - - /* Reload the function value registers. */ - emit_move_insn (valreg1, change_address (result, SImode, XEXP (result, 0))); - emit_move_insn (valreg2, - change_address (result, SImode, - plus_constant (XEXP (result, 0), 4))); - - /* Put USE insns before the return. */ - emit_insn (gen_rtx (USE, VOIDmode, valreg1)); - emit_insn (gen_rtx (USE, VOIDmode, valreg2)); - - /* Construct the return. */ - expand_null_return (); + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); DONE; }") -(define_insn "update_return" - [(unspec:SI [(match_operand:SI 0 "memory_operand" "m")] 0)] +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and +;; all of memory. This blocks insns from being moved across this point. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] 0)] "" - "frstor %0") + "") ;; Insn emitted into the body of a function to return from a function. ;; This is only done if the function's epilogue is known to be simple. @@ -4460,12 +5446,35 @@ "" "* { - rtx xops[2]; + rtx xops[3]; + static int ffssi_label_number; + char buffer[30]; xops[0] = operands[0]; - xops[1] = constm1_rtx; - output_asm_insn (AS2 (mov%L0,%1,%0), xops); - return AS2 (bsf%L0,%1,%0); + xops[1] = operands[1]; + xops[2] = constm1_rtx; + /* Can there be a way to avoid the jump here? */ + output_asm_insn (AS2 (bsf%L0,%1,%0), xops); +#ifdef LOCAL_LABEL_PREFIX + sprintf (buffer, \"jnz %sLFFSSI%d\", + LOCAL_LABEL_PREFIX, ffssi_label_number); +#else + sprintf (buffer, \"jnz %sLFFSSI%d\", + \"\", ffssi_label_number); +#endif + output_asm_insn (buffer, xops); + output_asm_insn (AS2 (mov%L0,%2,%0), xops); +#ifdef LOCAL_LABEL_PREFIX + sprintf (buffer, \"%sLFFSSI%d:\", + LOCAL_LABEL_PREFIX, ffssi_label_number); +#else + sprintf (buffer, \"%sLFFSSI%d:\", + \"\", ffssi_label_number); +#endif + output_asm_insn (buffer, xops); + + ffssi_label_number++; + return \"\"; }") (define_expand "ffshi2" @@ -4484,12 +5493,34 @@ "" "* { - rtx xops[2]; + rtx xops[3]; + static int ffshi_label_number; + char buffer[30]; xops[0] = operands[0]; - xops[1] = constm1_rtx; - output_asm_insn (AS2 (mov%W0,%1,%0), xops); - return AS2 (bsf%W0,%1,%0); + xops[1] = operands[1]; + xops[2] = constm1_rtx; + output_asm_insn (AS2 (bsf%W0,%1,%0), xops); +#ifdef LOCAL_LABEL_PREFIX + sprintf (buffer, \"jnz %sLFFSHI%d\", + LOCAL_LABEL_PREFIX, ffshi_label_number); +#else + sprintf (buffer, \"jnz %sLFFSHI%d\", + \"\", ffshi_label_number); +#endif + output_asm_insn (buffer, xops); + output_asm_insn (AS2 (mov%W0,%2,%0), xops); +#ifdef LOCAL_LABEL_PREFIX + sprintf (buffer, \"%sLFFSHI%d:\", + LOCAL_LABEL_PREFIX, ffshi_label_number); +#else + sprintf (buffer, \"%sLFFSHI%d:\", + \"\", ffshi_label_number); +#endif + output_asm_insn (buffer, xops); + + ffshi_label_number++; + return \"\"; }") ;; These patterns match the binary 387 instructions for addM3, subM3, @@ -4506,7 +5537,7 @@ [(match_operand:DF 1 "nonimmediate_operand" "0,fm") (match_operand:DF 2 "nonimmediate_operand" "fm,0")]))] "TARGET_80387" - "* return (char *) output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);") (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") @@ -4514,7 +5545,48 @@ [(float:DF (match_operand:SI 1 "general_operand" "rm")) (match_operand:DF 2 "general_operand" "0")]))] "TARGET_80387" - "* return (char *) output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (match_operator:XF 3 "binary_387_op" + [(match_operand:XF 1 "nonimmediate_operand" "0,f") + (match_operand:XF 2 "nonimmediate_operand" "f,0")]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (match_operator:XF 3 "binary_387_op" + [(float:XF (match_operand:SI 1 "general_operand" "rm")) + (match_operand:XF 2 "general_operand" "0")]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (match_operator:XF 3 "binary_387_op" + [(float_extend:XF (match_operand:SF 1 "general_operand" "fm,0")) + (match_operand:XF 2 "general_operand" "0,f")]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f") + (match_operator:XF 3 "binary_387_op" + [(match_operand:XF 1 "general_operand" "0") + (float:XF (match_operand:SI 2 "general_operand" "rm"))]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (match_operator:XF 3 "binary_387_op" + [(match_operand:XF 1 "general_operand" "0,f") + (float_extend:XF + (match_operand:SF 2 "general_operand" "fm,0"))]))] + "TARGET_80387" + "* return output_387_binary_op (insn, operands);") (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f,f") @@ -4522,7 +5594,7 @@ [(float_extend:DF (match_operand:SF 1 "general_operand" "fm,0")) (match_operand:DF 2 "general_operand" "0,f")]))] "TARGET_80387" - "* return (char *) output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);") (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") @@ -4530,7 +5602,7 @@ [(match_operand:DF 1 "general_operand" "0") (float:DF (match_operand:SI 2 "general_operand" "rm"))]))] "TARGET_80387" - "* return (char *) output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);") (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f,f") @@ -4539,7 +5611,7 @@ (float_extend:DF (match_operand:SF 2 "general_operand" "fm,0"))]))] "TARGET_80387" - "* return (char *) output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);") (define_insn "" [(set (match_operand:SF 0 "register_operand" "=f,f") @@ -4547,7 +5619,7 @@ [(match_operand:SF 1 "nonimmediate_operand" "0,fm") (match_operand:SF 2 "nonimmediate_operand" "fm,0")]))] "TARGET_80387" - "* return (char *) output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);") (define_insn "" [(set (match_operand:SF 0 "register_operand" "=f") @@ -4555,7 +5627,7 @@ [(float:SF (match_operand:SI 1 "general_operand" "rm")) (match_operand:SF 2 "general_operand" "0")]))] "TARGET_80387" - "* return (char *) output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);") (define_insn "" [(set (match_operand:SF 0 "register_operand" "=f") @@ -4563,7 +5635,7 @@ [(match_operand:SF 1 "general_operand" "0") (float:SF (match_operand:SI 2 "general_operand" "rm"))]))] "TARGET_80387" - "* return (char *) output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);") (define_expand "strlensi" [(parallel [(set (match_dup 4)