diff options
Diffstat (limited to 'contrib/gcc/config/i386/i386.md')
-rw-r--r-- | contrib/gcc/config/i386/i386.md | 4049 |
1 files changed, 3046 insertions, 1003 deletions
diff --git a/contrib/gcc/config/i386/i386.md b/contrib/gcc/config/i386/i386.md index ff0119631cb4..f85992fd2ca3 100644 --- a/contrib/gcc/config/i386/i386.md +++ b/contrib/gcc/config/i386/i386.md @@ -1,5 +1,5 @@ -;; GCC machine description for Intel X86. -;; Copyright (C) 1988, 1994, 1995 Free Software Foundation, Inc. +; GCC machine description for Intel X86. +;; Copyright (C) 1988, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. ;; Mostly by William Schelter. ;; This file is part of GNU CC. @@ -17,8 +17,7 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU CC; see the file COPYING. If not, write to ;; the Free Software Foundation, 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - +;; Boston, MA 02111-1307, USA. */ ;; The original PO technology requires these to be ordered by speed, ;; so that assigner will pick the fastest. @@ -37,8 +36,8 @@ ;; 'L' Print the opcode suffix for a 32-bit integer opcode. ;; 'W' Print the opcode suffix for a 16-bit integer opcode. ;; 'B' Print the opcode suffix for an 8-bit integer opcode. -;; 'S' Print the opcode suffix for a 32-bit float opcode. ;; 'Q' Print the opcode suffix for a 64-bit float opcode. +;; 'S' Print the opcode suffix for a 32-bit float opcode. ;; 'T' Print the opcode suffix for an 80-bit extended real XFmode float opcode. ;; 'J' Print the appropriate jump operand. @@ -59,6 +58,72 @@ ;; operand 0 is the argument for `sin'. ;; 2 This is a `cos' operation. The mode of the UNSPEC is MODE_FLOAT. ;; operand 0 is the argument for `cos'. +;; 3 This is part of a `stack probe' operation. The mode of the UNSPEC is +;; always SImode. operand 0 is the size of the stack allocation. +;; 4 This is the source of a fake SET of the frame pointer which is used to +;; prevent insns referencing it being scheduled across the initial +;; decrement of the stack pointer. +;; 5 This is a `bsf' operation. + +;; This shadows the processor_type enumeration, so changes must be made +;; to i386.h at the same time. + +(define_attr "type" "integer,idiv,imul,fld,fpop,fpdiv,fpmul" + (const_string "integer")) + +;; Functional units + +; (define_function_unit NAME MULTIPLICITY SIMULTANEITY +; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST]) + +; pentiumpro has a reservation station with 5 ports +; port 0 has integer, float add, integer divide, float divide, float +; multiply, and shifter units. +; port 1 has integer, and jump units. +; port 2 has the load address generation unit +; ports 3 and 4 have the store address generation units + +; pentium has two integer pipelines, the main u pipe and the secondary v pipe. +; and a float pipeline + +;; Floating point + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "fpop") (eq_attr "cpu" "i386,i486")) + 5 5) + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "fpop") (eq_attr "cpu" "pentium,pentiumpro")) + 3 0) + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentium")) + 7 0) + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentiumpro")) + 5 0) + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "idiv") (eq_attr "cpu" "pentiumpro")) + 10 10) + +(define_function_unit "fp" 1 0 + (and (eq_attr "type" "imul") (eq_attr "cpu" "pentiumpro")) + 6 0) + +(define_function_unit "fp" 1 0 + (eq_attr "type" "fpdiv") + 10 10) + +(define_function_unit "fp" 1 0 + (eq_attr "type" "fld") + 1 0) + +(define_function_unit "integer" 1 0 + (and (eq_attr "type" "integer") (eq_attr "cpu" "!i386")) + 2 0) + ;; "movl MEM,REG / testl REG,REG" is faster on a 486 than "cmpl $0,MEM". ;; But restricting MEM here would mean that gcc could not remove a redundant @@ -72,6 +137,12 @@ ;; actually generating RTL. The bCOND or sCOND (emitted immediately ;; after the tstM or cmp) will actually emit the tstM or cmpM. +;; Processor type -- this attribute must exactly match the processor_type +;; enumeration in i386.h. + +(define_attr "cpu" "i386,i486,pentium,pentiumpro" + (const (symbol_ref "ix86_cpu"))) + (define_insn "tstsi_1" [(set (cc0) (match_operand:SI 0 "nonimmediate_operand" "rm"))] @@ -93,6 +164,7 @@ { i386_compare_gen = gen_tstsi_1; i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; DONE; }") @@ -117,6 +189,7 @@ { i386_compare_gen = gen_tsthi_1; i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; DONE; }") @@ -141,6 +214,7 @@ { i386_compare_gen = gen_tstqi_1; i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; DONE; }") @@ -174,6 +248,7 @@ { i386_compare_gen = gen_tstsf_cc; i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; DONE; }") @@ -207,6 +282,7 @@ { i386_compare_gen = gen_tstdf_cc; i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; DONE; }") @@ -228,7 +304,7 @@ return output_fp_cc0_set (insn); }") -;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode +;; Don't generate tstxf if generating IEEE code, since the `ftst' opcode ;; isn't IEEE compliant. (define_expand "tstxf" @@ -240,6 +316,7 @@ { i386_compare_gen = gen_tstxf_cc; i386_compare_op0 = operands[0]; + i386_compare_op1 = const0_rtx; DONE; }") @@ -251,15 +328,7 @@ (compare (match_operand:SI 0 "nonimmediate_operand" "mr,r") (match_operand:SI 1 "general_operand" "ri,mr")))] "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM" - "* -{ - if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM) - { - cc_status.flags |= CC_REVERSED; - return AS2 (cmp%L0,%0,%1); - } - return AS2 (cmp%L0,%1,%0); -}") + "* return AS2 (cmp%L0,%1,%0);") (define_expand "cmpsi" [(set (cc0) @@ -282,15 +351,7 @@ (compare (match_operand:HI 0 "nonimmediate_operand" "mr,r") (match_operand:HI 1 "general_operand" "ri,mr")))] "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM" - "* -{ - if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM) - { - cc_status.flags |= CC_REVERSED; - return AS2 (cmp%W0,%0,%1); - } - return AS2 (cmp%W0,%1,%0); -}") + "* return AS2 (cmp%W0,%1,%0);") (define_expand "cmphi" [(set (cc0) @@ -313,15 +374,7 @@ (compare (match_operand:QI 0 "nonimmediate_operand" "q,mq") (match_operand:QI 1 "general_operand" "qm,nq")))] "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM" - "* -{ - if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM) - { - cc_status.flags |= CC_REVERSED; - return AS2 (cmp%B0,%0,%1); - } - return AS2 (cmp%B0,%1,%0); -}") + "* return AS2 (cmp%B0,%1,%0);") (define_expand "cmpqi" [(set (cc0) @@ -346,11 +399,10 @@ (define_insn "" [(set (cc0) (match_operator 2 "VOIDmode_compare_op" - [(match_operand:XF 0 "nonimmediate_operand" "f") - (match_operand:XF 1 "nonimmediate_operand" "f")])) + [(match_operand:XF 0 "register_operand" "f") + (match_operand:XF 1 "register_operand" "f")])) (clobber (match_scratch:HI 3 "=a"))] - "TARGET_80387 - && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)" + "TARGET_80387" "* return output_float_compare (insn, operands);") (define_insn "" @@ -386,6 +438,16 @@ (define_insn "" [(set (cc0) (match_operator 2 "VOIDmode_compare_op" + [(float_extend:XF + (match_operand:DF 0 "nonimmediate_operand" "fm")) + (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:SF 1 "nonimmediate_operand" "fm"))])) @@ -395,6 +457,16 @@ (define_insn "" [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(float_extend:XF + (match_operand:SF 0 "nonimmediate_operand" "fm")) + (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) (compare:CCFPEQ (match_operand:XF 0 "register_operand" "f") (match_operand:XF 1 "register_operand" "f"))) (clobber (match_scratch:HI 2 "=a"))] @@ -453,6 +525,16 @@ (define_insn "" [(set (cc0) + (match_operator 2 "VOIDmode_compare_op" + [(float_extend:DF + (match_operand:SF 0 "register_operand" "f")) + (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) (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f") (match_operand:DF 1 "register_operand" "f"))) (clobber (match_scratch:HI 2 "=a"))] @@ -520,7 +602,7 @@ (define_expand "cmpxf" [(set (cc0) (compare (match_operand:XF 0 "register_operand" "") - (match_operand:XF 1 "nonimmediate_operand" "")))] + (match_operand:XF 1 "register_operand" "")))] "TARGET_80387" " { @@ -534,28 +616,30 @@ (define_expand "cmpdf" [(set (cc0) (compare (match_operand:DF 0 "register_operand" "") - (match_operand:DF 1 "nonimmediate_operand" "")))] + (match_operand:DF 1 "general_operand" "")))] "TARGET_80387" " { i386_compare_gen = gen_cmpdf_cc; i386_compare_gen_eq = gen_cmpdf_ccfpeq; i386_compare_op0 = operands[0]; - i386_compare_op1 = operands[1]; + i386_compare_op1 = (immediate_operand (operands[1], DFmode)) + ? copy_to_mode_reg (DFmode, operands[1]) : operands[1]; DONE; }") (define_expand "cmpsf" [(set (cc0) (compare (match_operand:SF 0 "register_operand" "") - (match_operand:SF 1 "nonimmediate_operand" "")))] + (match_operand:SF 1 "general_operand" "")))] "TARGET_80387" " { i386_compare_gen = gen_cmpsf_cc; i386_compare_gen_eq = gen_cmpsf_ccfpeq; i386_compare_op0 = operands[0]; - i386_compare_op1 = operands[1]; + i386_compare_op1 = (immediate_operand (operands[1], SFmode)) + ? copy_to_mode_reg (SFmode, operands[1]) : operands[1]; DONE; }") @@ -573,11 +657,7 @@ (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) @@ -624,7 +704,7 @@ (define_insn "" [(set (cc0) (and:SI (match_operand:SI 0 "general_operand" "%ro") - (match_operand:SI 1 "general_operand" "ri")))] + (match_operand:SI 1 "nonmemory_operand" "ri")))] "" "* { @@ -682,7 +762,7 @@ (define_insn "" [(set (cc0) (and:HI (match_operand:HI 0 "general_operand" "%ro") - (match_operand:HI 1 "general_operand" "ri")))] + (match_operand:HI 1 "nonmemory_operand" "ri")))] "" "* { @@ -715,6 +795,12 @@ } } + /* use 32-bit test instruction if there are no sign issues */ + if (GET_CODE (operands[1]) == CONST_INT + && !(INTVAL (operands[1]) & ~0x7fff) + && i386_aligned_p (operands[0])) + return AS2 (test%L0,%1,%k0); + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) return AS2 (test%W0,%1,%0); @@ -723,8 +809,8 @@ (define_insn "" [(set (cc0) - (and:QI (match_operand:QI 0 "general_operand" "%qm") - (match_operand:QI 1 "general_operand" "qi")))] + (and:QI (match_operand:QI 0 "nonimmediate_operand" "%qm") + (match_operand:QI 1 "nonmemory_operand" "qi")))] "" "* { @@ -741,24 +827,23 @@ (define_insn "" [(set (match_operand:SI 0 "push_operand" "=<") - (match_operand:SI 1 "general_operand" "g"))] - "TARGET_386" - "push%L0 %1") - -;; On a 486, it is faster to move MEM to a REG and then push, rather than -;; push MEM directly. + (match_operand:SI 1 "nonmemory_operand" "rn"))] + "flag_pic" + "* return AS1 (push%L0,%1);") (define_insn "" [(set (match_operand:SI 0 "push_operand" "=<") (match_operand:SI 1 "nonmemory_operand" "ri"))] - "!TARGET_386 && TARGET_MOVE" - "push%L0 %1") + "!flag_pic" + "* return AS1 (push%L0,%1);") + +;; On a 386, it is faster to push MEM directly. (define_insn "" [(set (match_operand:SI 0 "push_operand" "=<") - (match_operand:SI 1 "general_operand" "ri"))] - "!TARGET_386 && !TARGET_MOVE" - "push%L0 %1") + (match_operand:SI 1 "memory_operand" "m"))] + "TARGET_PUSH_MEMORY" + "* return AS1 (push%L0,%1);") ;; General case of fullword move. @@ -790,8 +875,10 @@ (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)" + (match_operand:SI 1 "general_operand" "rn,im"))] + "((!TARGET_MOVE || GET_CODE (operands[0]) != MEM) + || (GET_CODE (operands[1]) != MEM)) + && flag_pic" "* { rtx link; @@ -810,29 +897,50 @@ /* Fastest way to change a 0 to a 1. */ return AS1 (inc%L0,%0); - if (flag_pic && SYMBOLIC_CONST (operands[1])) + if (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") + [(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)) + && !flag_pic" + "* +{ + rtx link; + if (operands[1] == const0_rtx && REG_P (operands[0])) + return AS2 (xor%L0,%0,%0); + + if (operands[1] == const1_rtx + && (link = find_reg_note (insn, REG_WAS_0, 0)) + /* Make sure the insn that stored the 0 is still present. */ + && ! INSN_DELETED_P (XEXP (link, 0)) + && GET_CODE (XEXP (link, 0)) != NOTE + /* Make sure cross jumping didn't happen here. */ + && no_labels_between_p (XEXP (link, 0), insn) + /* Make sure the reg hasn't been clobbered. */ + && ! reg_set_between_p (operands[0], XEXP (link, 0), insn)) + /* Fastest way to change a 0 to a 1. */ + return AS1 (inc%L0,%0); + + return AS2 (mov%L0,%1,%0); +}") (define_insn "" [(set (match_operand:HI 0 "push_operand" "=<") (match_operand:HI 1 "nonmemory_operand" "ri"))] - "!TARGET_386 && TARGET_MOVE" - "push%W0 %1") + "" + "* return AS1 (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") + (match_operand:HI 1 "memory_operand" "m"))] + "TARGET_PUSH_MEMORY" + "* return AS1 (push%W0,%1);") ;; On i486, an incl and movl are both faster than incw and movw. @@ -876,10 +984,21 @@ if (REG_P (operands[0])) { - if (REG_P (operands[1])) - return AS2 (mov%L0,%k1,%k0); - else if (CONSTANT_P (operands[1])) - return AS2 (mov%L0,%1,%k0); + if (i386_aligned_p (operands[1])) + { + operands[1] = i386_sext16_if_const (operands[1]); + return AS2 (mov%L0,%k1,%k0); + } + if (TARGET_PENTIUMPRO) + { + /* movzwl is faster than movw on the Pentium Pro, + * although not as fast as an aligned movl. */ +#ifdef INTEL_SYNTAX + return AS2 (movzx,%1,%k0); +#else + return AS2 (movz%W0%L0,%1,%k0); +#endif + } } return AS2 (mov%W0,%1,%0); @@ -932,27 +1051,17 @@ ;; the amount pushed up to a halfword. (define_insn "" [(set (match_operand:QI 0 "push_operand" "=<") - (match_operand:QI 1 "immediate_operand" "n"))] + (match_operand:QI 1 "const_int_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); -}") + "* 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])); + operands[1] = gen_rtx_REG (HImode, REGNO (operands[1])); return AS1 (push%W0,%1); }") @@ -978,14 +1087,14 @@ }") (define_insn "" - [(set (match_operand:QI 0 "general_operand" "=q,*r,qm") - (match_operand:QI 1 "general_operand" "*g,q,qn"))] + [(set (match_operand:QI 0 "nonimmediate_operand" "=q,*r,qm") + (match_operand:QI 1 "general_operand" "*g,*rn,qn"))] "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" "* { rtx link; if (operands[1] == const0_rtx && REG_P (operands[0])) - return AS2 (xor%B0,%0,%0); + return AS2 (xor%L0,%k0,%k0); if (operands[1] == const1_rtx && (link = find_reg_note (insn, REG_WAS_0, 0)) @@ -996,8 +1105,14 @@ && no_labels_between_p (XEXP (link, 0), insn) /* Make sure the reg hasn't been clobbered. */ && ! reg_set_between_p (operands[0], XEXP (link, 0), insn)) - /* Fastest way to change a 0 to a 1. */ - return AS1 (inc%B0,%0); + { + /* Fastest way to change a 0 to a 1. + If inc%B0 isn't allowed, use inc%L0. */ + if (NON_QI_REG_P (operands[0])) + return AS1 (inc%L0,%k0); + else + return AS1 (inc%B0,%0); + } /* 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])) @@ -1032,7 +1147,7 @@ }") (define_insn "" - [(set (strict_low_part (match_operand:QI 0 "general_operand" "+qm,q")) + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) (match_operand:QI 1 "general_operand" "*qn,m"))] "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" "* @@ -1042,6 +1157,7 @@ return AS2 (xor%B0,%0,%0); if (operands[1] == const1_rtx + && ! NON_QI_REG_P (operands[0]) && (link = find_reg_note (insn, REG_WAS_0, 0)) /* Make sure the insn that stored the 0 is still present. */ && ! INSN_DELETED_P (XEXP (link, 0)) @@ -1063,43 +1179,10 @@ return AS2 (mov%B0,%1,%0); }") -(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" +(define_insn "movsf_push" [(set (match_operand:SF 0 "push_operand" "=<,<") - (match_operand:SF 1 "general_operand" "gF,f"))] - "!TARGET_MOVE" + (match_operand:SF 1 "general_operand" "*rfF,m"))] + "GET_CODE (operands[1]) != MEM || reload_in_progress || reload_completed" "* { if (STACK_REG_P (operands[1])) @@ -1119,64 +1202,62 @@ output_asm_insn (AS1 (fstp%S0,%0), xops); else output_asm_insn (AS1 (fst%S0,%0), xops); + RET; } - return AS1 (push%L1,%1); + + return AS1 (push%L0,%1); }") -(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"))] +(define_insn "movsf_push_memory" + [(set (match_operand:SF 0 "push_operand" "=<") + (match_operand:SF 1 "memory_operand" "m"))] + "TARGET_PUSH_MEMORY" + "* return AS1 (push%L0,%1);") + +(define_expand "movsf" + [(set (match_operand:SF 0 "general_operand" "") + (match_operand:SF 1 "general_operand" ""))] "" - "* + " { - if (STACK_REG_P (operands[1])) + /* 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) { - rtx xops[3]; + operands[1] = force_reg (SFmode, operands[1]); + } - if (! STACK_TOP_P (operands[1])) - abort (); + /* 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. */ + else if ((reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) != MEM + && GET_CODE (operands[1]) == CONST_DOUBLE + && !standard_80387_constant_p (operands[1])) + { + rtx insn, note, fp_const; - xops[0] = AT_SP (SFmode); - xops[1] = GEN_INT (4); - xops[2] = stack_pointer_rtx; + fp_const = force_const_mem (SFmode, operands[1]); + if (flag_pic) + current_function_uses_pic_offset_table = 1; - output_asm_insn (AS2 (sub%L2,%1,%2), xops); + insn = emit_insn (gen_rtx_SET (SFmode, operands[0], fp_const)); + note = find_reg_note (insn, REG_EQUAL, NULL_RTX); - if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) - output_asm_insn (AS1 (fstp%S0,%0), xops); + if (note) + XEXP (note, 0) = operands[1]; else - output_asm_insn (AS1 (fst%S0,%0), xops); - RET; + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1], REG_NOTES (insn)); } - - 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); }") ;; For the purposes of regclass, prefer FLOAT_REGS. -(define_insn "movsf_normal" - [(set (match_operand:SF 0 "general_operand" "=*rfm,*rf,f,!*rm") +(define_insn "" + [(set (match_operand:SF 0 "nonimmediate_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)" "* @@ -1203,7 +1284,7 @@ if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0])) { - output_to_reg (operands[0], stack_top_dies); + output_to_reg (operands[0], stack_top_dies, 0); RET; } @@ -1228,7 +1309,9 @@ /* Handle all SFmode moves not involving the 387 */ return singlemove_string (operands); -}") +}" + [(set_attr "type" "fld")]) + (define_insn "swapsf" [(set (match_operand:SF 0 "register_operand" "f") @@ -1244,50 +1327,17 @@ 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" +(define_insn "movdf_push" [(set (match_operand:DF 0 "push_operand" "=<,<") - (match_operand:DF 1 "general_operand" "gF,f"))] - "!TARGET_MOVE" + (match_operand:DF 1 "general_operand" "*rfF,o"))] + "GET_CODE (operands[1]) != MEM || reload_in_progress || reload_completed" "* { if (STACK_REG_P (operands[1])) { rtx xops[3]; - xops[0] = AT_SP (SFmode); + xops[0] = AT_SP (DFmode); xops[1] = GEN_INT (8); xops[2] = stack_pointer_rtx; @@ -1300,56 +1350,65 @@ RET; } - else - return output_move_double (operands); + + if (which_alternative == 1) + return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 0, 0); + + 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"))] +(define_insn "movdf_push_memory" + [(set (match_operand:DF 0 "push_operand" "=<") + (match_operand:DF 1 "memory_operand" "o"))] + "TARGET_PUSH_MEMORY" + "* return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode),0,0);") + +(define_expand "movdf" + [(set (match_operand:DF 0 "general_operand" "") + (match_operand:DF 1 "general_operand" ""))] "" - "* + " { - if (STACK_REG_P (operands[1])) + /* 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) { - rtx xops[3]; + operands[1] = force_reg (DFmode, operands[1]); + } - xops[0] = AT_SP (SFmode); - xops[1] = GEN_INT (8); - xops[2] = stack_pointer_rtx; + /* 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. */ + else if ((reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) != MEM + && GET_CODE (operands[1]) == CONST_DOUBLE + && !standard_80387_constant_p (operands[1])) + { + rtx insn, note, fp_const; - output_asm_insn (AS2 (sub%L2,%1,%2), xops); + fp_const = force_const_mem (DFmode, operands[1]); + if (flag_pic) + current_function_uses_pic_offset_table = 1; - 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); + insn = emit_insn (gen_rtx_SET (DFmode, operands[0], fp_const)); + note = find_reg_note (insn, REG_EQUAL, NULL_RTX); - RET; + if (note) + XEXP (note, 0) = operands[1]; + else + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1], REG_NOTES (insn)); } - - else if (GET_CODE (operands[1]) != MEM) - return output_move_double (operands); - - else - 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") +(define_insn "" + [(set (match_operand:DF 0 "nonimmediate_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)" + "(!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; @@ -1374,7 +1433,7 @@ if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0])) { - output_to_reg (operands[0], stack_top_dies); + output_to_reg (operands[0], stack_top_dies, 0); RET; } @@ -1399,7 +1458,10 @@ /* Handle all DFmode moves not involving the 387 */ return output_move_double (operands); -}") +}" + [(set_attr "type" "fld")]) + + (define_insn "swapdf" [(set (match_operand:DF 0 "register_operand" "f") @@ -1415,109 +1477,87 @@ return AS1 (fxch,%0); }") -(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" +(define_insn "movxf_push" [(set (match_operand:XF 0 "push_operand" "=<,<") - (match_operand:XF 1 "general_operand" "gF,f"))] - "!TARGET_MOVE" + (match_operand:XF 1 "general_operand" "*rfF,o"))] + "GET_CODE (operands[1]) != MEM || reload_in_progress || reload_completed" "* { if (STACK_REG_P (operands[1])) { rtx xops[3]; - xops[0] = AT_SP (SFmode); + xops[0] = AT_SP (XFmode); 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); + + if (which_alternative == 1) + return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 0, 0); + + 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"))] +(define_insn "movxf_push_memory" + [(set (match_operand:XF 0 "push_operand" "=<") + (match_operand:XF 1 "memory_operand" "o"))] + "TARGET_PUSH_MEMORY" + "* return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode),0,0);") + +(define_expand "movxf" + [(set (match_operand:XF 0 "general_operand" "") + (match_operand:XF 1 "general_operand" ""))] "" - "* + " { - if (STACK_REG_P (operands[1])) + /* 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) { - rtx xops[3]; - - xops[0] = AT_SP (SFmode); - xops[1] = GEN_INT (12); - xops[2] = stack_pointer_rtx; + operands[1] = force_reg (XFmode, operands[1]); + } - 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); + /* 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. */ + else if ((reload_in_progress | reload_completed) == 0 + && GET_CODE (operands[0]) != MEM + && GET_CODE (operands[1]) == CONST_DOUBLE + && !standard_80387_constant_p (operands[1])) + { + rtx insn, note, fp_const; - RET; - } + fp_const = force_const_mem (XFmode, operands[1]); + if (flag_pic) + current_function_uses_pic_offset_table = 1; - else if (GET_CODE (operands[1]) != MEM - || GET_CODE (operands[2]) != REG) - return output_move_double (operands); + insn = emit_insn (gen_rtx_SET (XFmode, operands[0], fp_const)); + note = find_reg_note (insn, REG_EQUAL, NULL_RTX); - else - return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 2, 4); + if (note) + XEXP (note, 0) = operands[1]; + else + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1], REG_NOTES (insn)); + } }") -(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") +(define_insn "" + [(set (match_operand:XF 0 "nonimmediate_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)" + "(!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; @@ -1542,7 +1582,7 @@ if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0])) { - output_to_reg (operands[0], stack_top_dies); + output_to_reg (operands[0], stack_top_dies, 0); RET; } @@ -1570,7 +1610,7 @@ return output_move_double (operands); }") -(define_insn "swapxf" +(define_insn "swapxf" [(set (match_operand:XF 0 "register_operand" "f") (match_operand:XF 1 "register_operand" "f")) (set (match_dup 1) @@ -1585,36 +1625,40 @@ }") (define_insn "" - [(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"))] + [(set (match_operand:DI 0 "push_operand" "=<") + (match_operand:DI 1 "general_operand" "riF"))] "" - "* -{ - if (GET_CODE (operands[1]) != MEM) - return output_move_double (operands); + "* return output_move_double (operands);") - else - return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode), 2, 4); -}") +(define_insn "" + [(set (match_operand:DI 0 "push_operand" "=<") + (match_operand:DI 1 "memory_operand" "o"))] + "TARGET_PUSH_MEMORY" + "* return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode),0,0);") -(define_insn "movdi" - [(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"))] +(define_expand "movdi" + [(set (match_operand:DI 0 "general_operand" "") + (match_operand:DI 1 "general_operand" ""))] "" - "* + " { - 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); + /* 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 (DImode, operands[1]); + } }") +(define_insn "" + [(set (match_operand:DI 0 "general_operand" "=g,r") + (match_operand:DI 1 "general_operand" "riF,m"))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) + || (GET_CODE (operands[1]) != MEM)" + "* return output_move_double (operands);") + ;;- conversion instructions ;;- NONE @@ -1623,21 +1667,39 @@ ;; See comments by `andsi' for when andl is faster than movzx. (define_insn "zero_extendhisi2" - [(set (match_operand:SI 0 "general_operand" "=r") - (zero_extend:SI - (match_operand:HI 1 "nonimmediate_operand" "rm")))] + [(set (match_operand:SI 0 "register_operand" "=r,&r,?r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,rm,rm")))] "" "* -{ - if ((!TARGET_386 || REGNO (operands[0]) == 0) + { + rtx xops[2]; + + if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0) && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1])) { - rtx xops[2]; xops[0] = operands[0]; xops[1] = GEN_INT (0xffff); output_asm_insn (AS2 (and%L0,%1,%k0), xops); RET; } + if (TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1])) + { + output_asm_insn (AS2 (xor%L0,%0,%0),operands); + output_asm_insn (AS2 (mov%W0,%1,%w0),operands); + RET; + } + + if (TARGET_ZERO_EXTEND_WITH_AND) + { + xops[0] = operands[0]; + xops[1] = GEN_INT (0xffff); + if (i386_aligned_p (operands[1])) + output_asm_insn (AS2 (mov%L0,%k1,%k0),operands); + else + output_asm_insn (AS2 (mov%W0,%1,%w0),operands); + output_asm_insn (AS2 (and%L0,%1,%k0), xops); + RET; + } #ifdef INTEL_SYNTAX return AS2 (movzx,%1,%0); @@ -1646,23 +1708,62 @@ #endif }") +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (match_dup 0) + (const_int 0)) + (set (strict_low_part (match_dup 2)) + (match_dup 1))] + "operands[2] = gen_rtx_REG (HImode, true_regnum (operands[0]));") + + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "memory_operand" "")))] + "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (strict_low_part (match_dup 2)) + (match_dup 1)) + (set (match_dup 0) + (and:SI (match_dup 0) + (const_int 65535)))] + "operands[2] = gen_rtx_REG (HImode, true_regnum (operands[0]));") + (define_insn "zero_extendqihi2" - [(set (match_operand:HI 0 "general_operand" "=r") - (zero_extend:HI - (match_operand:QI 1 "nonimmediate_operand" "qm")))] + [(set (match_operand:HI 0 "register_operand" "=q,&q,?r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))] "" "* -{ - if ((!TARGET_386 || REGNO (operands[0]) == 0) - && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1])) + { + rtx xops[2]; + + if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0) + && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) { - rtx xops[2]; xops[0] = operands[0]; xops[1] = GEN_INT (0xff); output_asm_insn (AS2 (and%L0,%1,%k0), xops); RET; } - + if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0])) + { + if(!reg_overlap_mentioned_p(operands[0],operands[1])) + { + output_asm_insn (AS2 (xor%L0,%k0,%k0), operands); + output_asm_insn (AS2 (mov%B0,%1,%b0), operands); + } + else + { + xops[0] = operands[0]; + xops[1] = GEN_INT (0xff); + output_asm_insn (AS2 (mov%B0,%1,%b0),operands); + output_asm_insn (AS2 (and%L0,%1,%k0), xops); + } + RET; + } + #ifdef INTEL_SYNTAX return AS2 (movzx,%1,%0); #else @@ -1670,22 +1771,89 @@ #endif }") +(define_split + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] + "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND + && !reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (match_dup 0) + (const_int 0)) + (set (strict_low_part (match_dup 2)) + (match_dup 1))] + "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));") + + +(define_split + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "memory_operand" "")))] + "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND + && reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (strict_low_part (match_dup 2)) + (match_dup 1)) + (set (match_dup 0) + (and:HI (match_dup 0) + (const_int 255)))] + "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));") + +(define_split + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "register_operand" "")))] + "reload_completed && TARGET_ZERO_EXTEND_WITH_AND" + [(set (match_dup 0) + (match_dup 2)) + (set (match_dup 0) + (and:HI (match_dup 0) + (const_int 255)))] + "if (GET_CODE (operands[1]) == SUBREG && SUBREG_WORD (operands[1]) == 0) + operands[1] = SUBREG_REG (operands[1]); + if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG + || REGNO (operands[0]) == REGNO (operands[1])) + FAIL; + operands[2] = gen_rtx_REG (HImode, REGNO (operands[1]));") + (define_insn "zero_extendqisi2" - [(set (match_operand:SI 0 "general_operand" "=r") - (zero_extend:SI - (match_operand:QI 1 "nonimmediate_operand" "qm")))] + [(set (match_operand:SI 0 "register_operand" "=q,&q,?r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))] "" "* -{ - if ((!TARGET_386 || REGNO (operands[0]) == 0) - && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1])) + { + rtx xops[2]; + + if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0) + && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) { - rtx xops[2]; xops[0] = operands[0]; xops[1] = GEN_INT (0xff); output_asm_insn (AS2 (and%L0,%1,%k0), xops); RET; } + if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0])) + { + if(!reg_overlap_mentioned_p (operands[0], operands[1])) + { + output_asm_insn (AS2 (xor%L0,%0,%0),operands); + output_asm_insn (AS2 (mov%B0,%1,%b0),operands); + } + else + { + xops[0] = operands[0]; + xops[1] = GEN_INT (0xff); + output_asm_insn (AS2 (mov%B0,%1,%b0), operands); + output_asm_insn (AS2 (and%L0,%1,%k0), xops); + } + RET; + } + + if (TARGET_ZERO_EXTEND_WITH_AND && GET_CODE (operands[1]) == REG) + { + xops[0] = operands[0]; + xops[1] = GEN_INT (0xff); + operands[1] = gen_rtx_REG (SImode, REGNO (operands[1])); + output_asm_insn (AS2 (mov%L0,%1,%0), operands); + output_asm_insn (AS2 (and%L0,%1,%k0), xops); + RET; + } #ifdef INTEL_SYNTAX return AS2 (movzx,%1,%0); @@ -1694,23 +1862,77 @@ #endif }") +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND + && !reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (match_dup 0) + (const_int 0)) + (set (strict_low_part (match_dup 2)) + (match_dup 1))] + "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));") + + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "memory_operand" "")))] + "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND + && reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (strict_low_part (match_dup 2)) + (match_dup 1)) + (set (match_dup 0) + (and:SI (match_dup 0) + (const_int 255)))] + "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "register_operand" "")))] + "reload_completed && TARGET_ZERO_EXTEND_WITH_AND + && ! reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (match_dup 0) + (match_dup 2)) + (set (match_dup 0) + (and:SI (match_dup 0) + (const_int 255)))] + "operands[2] = gen_rtx_REG (SImode, true_regnum (operands[1]));") + (define_insn "zero_extendsidi2" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (match_operand:SI 1 "register_operand" "0")))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?m") + (zero_extend:DI (match_operand:SI 1 "register_operand" "0,rm,r")))] "" "* -{ - operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); - return AS2 (xor%L0,%0,%0); + { + rtx high[2], low[2], xops[4]; + + if (REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) + { + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + return AS2 (xor%L0,%0,%0); + } + + split_di (operands, 1, low, high); + xops[0] = low[0]; + xops[1] = operands[1]; + xops[2] = high[0]; + xops[3] = const0_rtx; + + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + if (GET_CODE (low[0]) == MEM) + output_asm_insn (AS2 (mov%L2,%3,%2), xops); + else + output_asm_insn (AS2 (xor%L2,%2,%2), xops); + + RET; }") ;;- sign extension instructions (define_insn "extendsidi2" [(set (match_operand:DI 0 "register_operand" "=r") - (sign_extend:DI - (match_operand:SI 1 "register_operand" "0")))] + (sign_extend:DI (match_operand:SI 1 "register_operand" "0")))] "" "* { @@ -1724,7 +1946,7 @@ #endif } - operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); + operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); output_asm_insn (AS2 (mov%L0,%0,%1), operands); operands[0] = GEN_INT (31); @@ -1736,9 +1958,8 @@ ;; We use what the Unix assembler expects. (define_insn "extendhisi2" - [(set (match_operand:SI 0 "general_operand" "=r") - (sign_extend:SI - (match_operand:HI 1 "nonimmediate_operand" "rm")))] + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))] "" "* { @@ -1758,9 +1979,8 @@ }") (define_insn "extendqihi2" - [(set (match_operand:HI 0 "general_operand" "=r") - (sign_extend:HI - (match_operand:QI 1 "nonimmediate_operand" "qm")))] + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))] "" "* { @@ -1776,9 +1996,8 @@ }") (define_insn "extendqisi2" - [(set (match_operand:SI 0 "general_operand" "=r") - (sign_extend:SI - (match_operand:QI 1 "nonimmediate_operand" "qm")))] + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))] "" "* { @@ -1788,13 +2007,72 @@ return AS2 (movs%B0%L0,%1,%0); #endif }") + + +;; Truncation of long long -> 32 bit + +(define_expand "truncdisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m") + (truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))] + "" + " +{ + /* 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) + { + rtx target = gen_reg_rtx (SImode); + emit_insn (gen_truncdisi2 (target, operands[1])); + emit_move_insn (operands[0], target); + DONE; + } +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m") + (truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" + "* +{ + rtx low[2], high[2], xops[2]; + + split_di (&operands[1], 1, low, high); + xops[0] = operands[0]; + xops[1] = low[0]; + if (!rtx_equal_p (xops[0], xops[1])) + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + + RET; +}") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m") + (truncate:SI (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r") + (const_int 32))))] + "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)" + "* +{ + rtx low[2], high[2], xops[2]; + + split_di (&operands[1], 1, low, high); + xops[0] = operands[0]; + xops[1] = high[0]; + if (!rtx_equal_p (xops[0], xops[1])) + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + + RET; +}") + + ;; Conversions between float and double. (define_insn "extendsfdf2" - [(set (match_operand:DF 0 "general_operand" "=fm,f") + [(set (match_operand:DF 0 "nonimmediate_operand" "=fm,f") (float_extend:DF - (match_operand:SF 1 "general_operand" "f,fm")))] + (match_operand:SF 1 "nonimmediate_operand" "f,fm")))] "TARGET_80387" "* { @@ -1808,7 +2086,7 @@ if (NON_STACK_REG_P (operands[0])) { - output_to_reg (operands[0], stack_top_dies); + output_to_reg (operands[0], stack_top_dies, 0); RET; } @@ -1827,9 +2105,9 @@ }") (define_insn "extenddfxf2" - [(set (match_operand:XF 0 "general_operand" "=fm,f,f,!*r") + [(set (match_operand:XF 0 "nonimmediate_operand" "=fm,f,f,!*r") (float_extend:XF - (match_operand:DF 1 "general_operand" "f,fm,!*r,f")))] + (match_operand:DF 1 "nonimmediate_operand" "f,fm,!*r,f")))] "TARGET_80387" "* { @@ -1843,7 +2121,7 @@ if (NON_STACK_REG_P (operands[0])) { - output_to_reg (operands[0], stack_top_dies); + output_to_reg (operands[0], stack_top_dies, 0); RET; } @@ -1862,9 +2140,9 @@ }") (define_insn "extendsfxf2" - [(set (match_operand:XF 0 "general_operand" "=fm,f,f,!*r") + [(set (match_operand:XF 0 "nonimmediate_operand" "=fm,f,f,!*r") (float_extend:XF - (match_operand:SF 1 "general_operand" "f,fm,!*r,f")))] + (match_operand:SF 1 "nonimmediate_operand" "f,fm,!*r,f")))] "TARGET_80387" "* { @@ -1878,7 +2156,7 @@ if (NON_STACK_REG_P (operands[0])) { - output_to_reg (operands[0], stack_top_dies); + output_to_reg (operands[0], stack_top_dies, 0); RET; } @@ -1939,7 +2217,7 @@ }") (define_insn "truncxfsf2" - [(set (match_operand:SF 0 "general_operand" "=m,!*r") + [(set (match_operand:SF 0 "nonimmediate_operand" "=m,!*r") (float_truncate:SF (match_operand:XF 1 "register_operand" "f,f")))] "TARGET_80387" @@ -1954,7 +2232,7 @@ output_asm_insn (AS1 (fld,%y1), operands); stack_top_dies = 1; } - output_to_reg (operands[0], stack_top_dies); + output_to_reg (operands[0], stack_top_dies, 0); RET; } else if (GET_CODE (operands[0]) == MEM) @@ -1972,7 +2250,7 @@ }") (define_insn "truncxfdf2" - [(set (match_operand:DF 0 "general_operand" "=m,!*r") + [(set (match_operand:DF 0 "nonimmediate_operand" "=m,!*r") (float_truncate:DF (match_operand:XF 1 "register_operand" "f,f")))] "TARGET_80387" @@ -1987,7 +2265,7 @@ output_asm_insn (AS1 (fld,%y1), operands); stack_top_dies = 1; } - output_to_reg (operands[0], stack_top_dies); + output_to_reg (operands[0], stack_top_dies, 0); RET; } else if (GET_CODE (operands[0]) == MEM) @@ -2029,7 +2307,7 @@ 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); + operands[6] = (rtx) assign_386_stack_local (DImode, 1); }") (define_expand "fixuns_truncdfsi2" @@ -2050,7 +2328,7 @@ operands[3] = gen_lowpart (SImode, operands[2]); operands[4] = gen_reg_rtx (DFmode); operands[5] = (rtx) assign_386_stack_local (SImode, 0); - operands[6] = (rtx) assign_386_stack_local (SImode, 1); + operands[6] = (rtx) assign_386_stack_local (DImode, 1); }") (define_expand "fixuns_truncsfsi2" @@ -2071,7 +2349,7 @@ operands[3] = gen_lowpart (SImode, operands[2]); operands[4] = gen_reg_rtx (SFmode); operands[5] = (rtx) assign_386_stack_local (SImode, 0); - operands[6] = (rtx) assign_386_stack_local (SImode, 1); + operands[6] = (rtx) assign_386_stack_local (DImode, 1); }") ;; Signed conversion to DImode. @@ -2091,7 +2369,7 @@ 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); + operands[4] = (rtx) assign_386_stack_local (DImode, 1); }") (define_expand "fix_truncdfdi2" @@ -2109,7 +2387,7 @@ operands[1] = copy_to_mode_reg (DFmode, operands[1]); operands[2] = gen_reg_rtx (DFmode); operands[3] = (rtx) assign_386_stack_local (SImode, 0); - operands[4] = (rtx) assign_386_stack_local (SImode, 1); + operands[4] = (rtx) assign_386_stack_local (DImode, 1); }") (define_expand "fix_truncsfdi2" @@ -2127,37 +2405,37 @@ operands[1] = copy_to_mode_reg (SFmode, operands[1]); operands[2] = gen_reg_rtx (SFmode); operands[3] = (rtx) assign_386_stack_local (SImode, 0); - operands[4] = (rtx) assign_386_stack_local (SImode, 1); + operands[4] = (rtx) assign_386_stack_local (DImode, 1); }") ;; These match a signed conversion of either DFmode or SFmode to DImode. (define_insn "" - [(set (match_operand:DI 0 "general_operand" "=rm") - (fix:DI (fix:XF (match_operand:XF 1 "register_operand" "f")))) + [(set (match_operand:DI 0 "nonimmediate_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_operand:DI 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")))) + [(set (match_operand:DI 0 "nonimmediate_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_operand:DI 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:SF (match_operand:SF 1 "register_operand" "f")))) + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (fix:DI (fix:SF (match_operand:SF 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_operand:DI 3 "memory_operand" "m")) (clobber (match_scratch:SI 4 "=&q"))] "TARGET_80387" "* return output_fix_trunc (insn, operands);") @@ -2175,7 +2453,7 @@ " { operands[2] = (rtx) assign_386_stack_local (SImode, 0); - operands[3] = (rtx) assign_386_stack_local (SImode, 1); + operands[3] = (rtx) assign_386_stack_local (DImode, 1); }") (define_expand "fix_truncdfsi2" @@ -2189,7 +2467,7 @@ " { operands[2] = (rtx) assign_386_stack_local (SImode, 0); - operands[3] = (rtx) assign_386_stack_local (SImode, 1); + operands[3] = (rtx) assign_386_stack_local (DImode, 1); }") (define_expand "fix_truncsfsi2" @@ -2203,32 +2481,32 @@ " { operands[2] = (rtx) assign_386_stack_local (SImode, 0); - operands[3] = (rtx) assign_386_stack_local (SImode, 1); + operands[3] = (rtx) assign_386_stack_local (DImode, 1); }") (define_insn "" - [(set (match_operand:SI 0 "general_operand" "=rm") + [(set (match_operand:SI 0 "nonimmediate_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_operand:DI 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") + [(set (match_operand:SI 0 "nonimmediate_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_operand:DI 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") + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f")))) (clobber (match_operand:SI 2 "memory_operand" "m")) - (clobber (match_operand:SI 3 "memory_operand" "m")) + (clobber (match_operand:DI 3 "memory_operand" "m")) (clobber (match_scratch:SI 4 "=&q"))] "TARGET_80387" "* return output_fix_trunc (insn, operands);") @@ -2271,14 +2549,14 @@ (define_expand "floatdixf2" [(set (match_operand:XF 0 "register_operand" "") (float:XF (match_operand:DI 1 "nonimmediate_operand" "")))] - "TARGET_80387" + "TARGET_80387 && LONG_DOUBLE_TYPE_SIZE == 96" "") ;; 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")))] + (float:XF (match_operand:DI 1 "nonimmediate_operand" "rm")))] "TARGET_80387" "* { @@ -2346,7 +2624,7 @@ (define_insn "" [(set (match_operand:XF 0 "register_operand" "=f,f") - (float:XF (match_operand:SI 1 "general_operand" "m,!*r")))] + (float:XF (match_operand:SI 1 "nonimmediate_operand" "m,!*r")))] "TARGET_80387" "* { @@ -2380,11 +2658,137 @@ ;;- add instructions +(define_insn "addsidi3_1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,!&r,!r,o,!o") + (plus:DI (match_operand:DI 1 "general_operand" "0,0,0,o,riF,riF,o") + (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,roi,roi,ri,ri")))) + (clobber (match_scratch:SI 3 "=X,X,X,X,X,X,&r"))] + "" + "* +{ + rtx low[3], high[3], xops[7], temp; + + CC_STATUS_INIT; + + split_di (operands, 2, low, high); + high[2] = const0_rtx; + low[2] = operands[2]; + + 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; + } + } + + output_asm_insn (AS2 (add%L0,%2,%0), low); + output_asm_insn (AS2 (adc%L0,%2,%0), high); + RET; +}") + +(define_insn "addsidi3_2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,&r,!&r,&r,o,o,!o") + (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,o,o,ri,ri,i,r")) + (match_operand:DI 1 "general_operand" "0,0,0,iF,ro,roiF,riF,o,o"))) + (clobber (match_scratch:SI 3 "=X,X,X,X,X,X,X,&r,&r"))] + "" + "* +{ + rtx low[3], high[3], xops[7], temp; + + CC_STATUS_INIT; + + split_di (operands, 2, low, high); + high[2] = const0_rtx; + low[2] = operands[2]; + + 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) + { + if (rtx_equal_p (low[0], operands[2])) + { + output_asm_insn (AS2 (mov%L0,%2,%0), high); + output_asm_insn (AS2 (add%L0,%1,%0), low); + output_asm_insn (AS2 (adc%L0,%1,%0), high); + RET; + } + if (rtx_equal_p (high[0], operands[2])) + { + if (GET_CODE (operands[0]) != MEM) + { + output_asm_insn (AS2 (mov%L0,%2,%0), low); + output_asm_insn (AS2 (mov%L0,%2,%0), high); + output_asm_insn (AS2 (add%L0,%1,%0), low); + output_asm_insn (AS2 (adc%L0,%1,%0), high); + } + else + { + /* It's too late to ask for a scratch now - but this + will probably not happen too often. */ + output_asm_insn (AS2 (add%L1,%2,%1), low); + output_asm_insn (AS2 (mov%L0,%1,%0), low); + output_asm_insn (AS2 (mov%L1,%2,%1), low); + output_asm_insn (AS2 (mov%L0,%2,%0), high); + output_asm_insn (AS2 (adc%L0,%1,%0), high); + output_asm_insn (AS2 (sub%L1,%0,%1), low); + output_asm_insn (AS1 (neg%L1,%1), low); + } + RET; + } + 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; + } + } + + output_asm_insn (AS2 (add%L0,%2,%0), low); + output_asm_insn (AS2 (adc%L0,%2,%0), high); + RET; +}") + (define_insn "adddi3" - [(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,&r,&r,X,&r,&r,&r"))] + [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o") + (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o") + (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o"))) + (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))] "" "* { @@ -2456,14 +2860,23 @@ ;; On a 486, it is faster to do movl/addl than to do a single leal if ;; operands[1] and operands[2] are both registers. -(define_insn "addsi3" - [(set (match_operand:SI 0 "general_operand" "=?r,rm,r") - (plus:SI (match_operand:SI 1 "general_operand" "%r,0,0") - (match_operand:SI 2 "general_operand" "ri,ri,rm")))] +(define_expand "addsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" "")))] "" + "IX86_EXPAND_BINARY_OPERATOR (PLUS, SImode, operands);") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm,r") + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,r") + (match_operand:SI 2 "general_operand" "rmi,ri,ri")))] + "ix86_binary_operator_ok (PLUS, SImode, operands)" "* { - if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1])) + if (REG_P (operands[0]) && REG_P (operands[1]) + && (REG_P (operands[2]) || GET_CODE (operands[2]) == CONST_INT) + && REGNO (operands[0]) != REGNO (operands[1])) { if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2])) return AS2 (add%L0,%1,%0); @@ -2483,34 +2896,85 @@ operands[1] = SET_SRC (PATTERN (insn)); return AS2 (lea%L0,%a1,%0); } - - output_asm_insn (AS2 (mov%L0,%1,%0), operands); } + if (!rtx_equal_p (operands[0], operands[1])) + output_asm_insn (AS2 (mov%L0,%1,%0), operands); + if (operands[2] == const1_rtx) return AS1 (inc%L0,%0); if (operands[2] == constm1_rtx) return AS1 (dec%L0,%0); + /* subl $-128,%ebx is smaller than addl $128,%ebx. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 128) + { + /* This doesn't compute the carry bit in the same way + * as add%L0, but we use inc and dec above and they + * don't set the carry bit at all. If inc/dec don't need + * a CC_STATUS_INIT, this doesn't either... */ + operands[2] = GEN_INT (-128); + return AS2 (sub%L0,%2,%0); + } + return AS2 (add%L0,%2,%0); }") +;; addsi3 is faster, so put this after. + +(define_insn "movsi_lea" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:QI 1 "address_operand" "p"))] + "" + "* +{ + /* Adding a constant to a register is faster with an add. */ + /* ??? can this ever happen? */ + if (GET_CODE (operands[1]) == PLUS + && GET_CODE (XEXP (operands[1], 1)) == CONST_INT + && rtx_equal_p (operands[0], XEXP (operands[1], 0))) + { + operands[1] = XEXP (operands[1], 1); + + if (operands[1] == const1_rtx) + return AS1 (inc%L0,%0); + + if (operands[1] == constm1_rtx) + return AS1 (dec%L0,%0); + + return AS2 (add%L0,%1,%0); + } + + CC_STATUS_INIT; + return AS2 (lea%L0,%a1,%0); +}") + ;; ??? `lea' here, for three operand add? If leaw is used, only %bx, ;; %si and %di can appear in SET_SRC, and output_asm_insn might not be ;; able to handle the operand. But leal always works? -(define_insn "addhi3" - [(set (match_operand:HI 0 "general_operand" "=rm,r") - (plus:HI (match_operand:HI 1 "general_operand" "%0,0") - (match_operand:HI 2 "general_operand" "ri,rm")))] +(define_expand "addhi3" + [(set (match_operand:HI 0 "general_operand" "") + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" "")))] "" + "IX86_EXPAND_BINARY_OPERATOR (PLUS, HImode, operands);") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "ri,rm")))] + "ix86_binary_operator_ok (PLUS, HImode, operands)" "* { /* ??? what about offsettable memory references? */ - if (QI_REG_P (operands[0]) + if (!TARGET_PENTIUMPRO /* partial stalls are just too painful to risk. */ + && QI_REG_P (operands[0]) && GET_CODE (operands[2]) == CONST_INT - && (INTVAL (operands[2]) & 0xff) == 0) + && (INTVAL (operands[2]) & 0xff) == 0 + && i386_cc_probably_useless_p (insn)) { int byteval = (INTVAL (operands[2]) >> 8) & 0xff; CC_STATUS_INIT; @@ -2524,6 +2988,28 @@ return AS2 (add%B0,%2,%h0); } + /* Use a 32-bit operation when possible, to avoid the prefix penalty. */ + if (REG_P (operands[0]) + && i386_aligned_p (operands[2]) + && i386_cc_probably_useless_p (insn)) + { + CC_STATUS_INIT; + + if (GET_CODE (operands[2]) == CONST_INT) + { + HOST_WIDE_INT intval = 0xffff & INTVAL (operands[2]); + + if (intval == 1) + return AS1 (inc%L0,%k0); + + if (intval == 0xffff) + return AS1 (dec%L0,%k0); + + operands[2] = i386_sext16_if_const (operands[2]); + } + return AS2 (add%L0,%k2,%k0); + } + if (operands[2] == const1_rtx) return AS1 (inc%W0,%0); @@ -2535,11 +3021,18 @@ return AS2 (add%W0,%2,%0); }") -(define_insn "addqi3" - [(set (match_operand:QI 0 "general_operand" "=qm,q") - (plus:QI (match_operand:QI 1 "general_operand" "%0,0") - (match_operand:QI 2 "general_operand" "qn,qmn")))] +(define_expand "addqi3" + [(set (match_operand:QI 0 "general_operand" "") + (plus:QI (match_operand:QI 1 "general_operand" "") + (match_operand:QI 2 "general_operand" "")))] "" + "IX86_EXPAND_BINARY_OPERATOR (PLUS, QImode, operands);") + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qn,qmn")))] + "ix86_binary_operator_ok (PLUS, QImode, operands)" "* { if (operands[2] == const1_rtx) @@ -2563,8 +3056,8 @@ ; ;(define_insn "" ; [(set (match_operand:SI 0 "push_operand" "=<") -; (plus:SI (match_operand:SI 1 "general_operand" "%r") -; (match_operand:SI 2 "general_operand" "ri")))] +; (plus:SI (match_operand:SI 1 "register_operand" "%r") +; (match_operand:SI 2 "nonmemory_operand" "ri")))] ; "" ; "* ;{ @@ -2572,46 +3065,18 @@ ; xops[0] = operands[0]; ; xops[1] = operands[1]; ; xops[2] = operands[2]; -; xops[3] = gen_rtx (MEM, SImode, stack_pointer_rtx); +; xops[3] = gen_rtx_MEM (SImode, stack_pointer_rtx); ; output_asm_insn (\"push%z1 %1\", xops); ; output_asm_insn (AS2 (add%z3,%2,%3), xops); ; RET; ;}") -;; addsi3 is faster, so put this after. - -(define_insn "movsi_lea" - [(set (match_operand:SI 0 "register_operand" "=r") - (match_operand:QI 1 "address_operand" "p"))] - "" - "* -{ - CC_STATUS_INIT; - /* Adding a constant to a register is faster with an add. */ - /* ??? can this ever happen? */ - if (GET_CODE (operands[1]) == PLUS - && GET_CODE (XEXP (operands[1], 1)) == CONST_INT - && rtx_equal_p (operands[0], XEXP (operands[1], 0))) - { - operands[1] = XEXP (operands[1], 1); - - if (operands[1] == const1_rtx) - return AS1 (inc%L0,%0); - - if (operands[1] == constm1_rtx) - return AS1 (dec%L0,%0); - - return AS2 (add%L0,%1,%0); - } - return AS2 (lea%L0,%a1,%0); -}") - ;; 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" "")))] + (plus:XF (match_operand:XF 1 "register_operand" "") + (match_operand:XF 2 "register_operand" "")))] "TARGET_80387" "") @@ -2631,11 +3096,59 @@ ;;- subtract instructions +(define_insn "subsidi3" + [(set (match_operand:DI 0 "general_operand" "=&r,&ro,&r,!&r,o,o,!o") + (minus:DI (match_operand:DI 1 "general_operand" "0iF,0,roiF,roiF,riF,o,o") + (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,o,ri,i,r")))) + (clobber (match_scratch:SI 3 "=X,X,X,X,X,&r,&r"))] + "" + "* +{ + rtx low[3], high[3], xops[7]; + + CC_STATUS_INIT; + + split_di (operands, 2, low, high); + high[2] = const0_rtx; + low[2] = operands[2]; + + 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; + } + } + + output_asm_insn (AS2 (sub%L0,%2,%0), low); + output_asm_insn (AS2 (sbb%L0,%2,%0), high); + RET; +}") + (define_insn "subdi3" - [(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,&r,&r"))] + [(set (match_operand:DI 0 "general_operand" "=&r,&ro,o,o,!&r,!o") + (minus:DI (match_operand:DI 1 "general_operand" "0,0,0iF,or,roiF,roiF") + (match_operand:DI 2 "general_operand" "or,riF,or,iF,roiF,roiF"))) + (clobber (match_scratch:SI 3 "=X,X,&r,&r,X,&r"))] "" "* { @@ -2698,33 +3211,65 @@ RET; }") -(define_insn "subsi3" - [(set (match_operand:SI 0 "general_operand" "=rm,r") - (minus:SI (match_operand:SI 1 "general_operand" "0,0") - (match_operand:SI 2 "general_operand" "ri,rm")))] +(define_expand "subsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (minus:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" "")))] "" + "IX86_EXPAND_BINARY_OPERATOR (MINUS, SImode, operands);") + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] + "ix86_binary_operator_ok (MINUS, SImode, operands)" "* return AS2 (sub%L0,%2,%0);") -(define_insn "subhi3" - [(set (match_operand:HI 0 "general_operand" "=rm,r") - (minus:HI (match_operand:HI 1 "general_operand" "0,0") +(define_expand "subhi3" + [(set (match_operand:HI 0 "general_operand" "") + (minus:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" "")))] + "" + "IX86_EXPAND_BINARY_OPERATOR (MINUS, HImode, operands);") + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") (match_operand:HI 2 "general_operand" "ri,rm")))] + "ix86_binary_operator_ok (MINUS, HImode, operands)" + "* +{ + if (REG_P (operands[0]) + && i386_aligned_p (operands[2]) + && i386_cc_probably_useless_p (insn)) + { + CC_STATUS_INIT; + operands[2] = i386_sext16_if_const (operands[2]); + return AS2 (sub%L0,%k2,%k0); + } + return AS2 (sub%W0,%2,%0); +}") + +(define_expand "subqi3" + [(set (match_operand:QI 0 "general_operand" "") + (minus:QI (match_operand:QI 1 "general_operand" "") + (match_operand:QI 2 "general_operand" "")))] "" - "* return AS2 (sub%W0,%2,%0);") + "IX86_EXPAND_BINARY_OPERATOR (MINUS, QImode, operands);") -(define_insn "subqi3" - [(set (match_operand:QI 0 "general_operand" "=qm,q") - (minus:QI (match_operand:QI 1 "general_operand" "0,0") +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") + (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") (match_operand:QI 2 "general_operand" "qn,qmn")))] - "" + "ix86_binary_operator_ok (MINUS, QImode, operands)" "* return AS2 (sub%B0,%2,%0);") ;; 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" "")))] + (minus:XF (match_operand:XF 1 "register_operand" "") + (match_operand:XF 2 "register_operand" "")))] "TARGET_80387" "") @@ -2745,22 +3290,15 @@ ;;- multiply instructions ;(define_insn "mulqi3" -; [(set (match_operand:QI 0 "general_operand" "=a") -; (mult:QI (match_operand:QI 1 "general_operand" "%0") -; (match_operand:QI 2 "general_operand" "qm")))] +; [(set (match_operand:QI 0 "register_operand" "=a") +; (mult:QI (match_operand:QI 1 "register_operand" "%0") +; (match_operand:QI 2 "nonimmediate_operand" "qm")))] ; "" ; "imul%B0 %2,%0") -(define_insn "" - [(set (match_operand:HI 0 "general_operand" "=r") - (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:HI (match_operand:HI 1 "general_operand" "%0,rm") + [(set (match_operand:HI 0 "register_operand" "=r,r") + (mult:HI (match_operand:HI 1 "nonimmediate_operand" "%0,rm") (match_operand:HI 2 "general_operand" "g,i")))] "" "* @@ -2771,18 +3309,12 @@ /* Assembler has weird restrictions. */ return AS2 (imul%W0,%2,%0); return AS3 (imul%W0,%2,%1,%0); -}") - -(define_insn "" - [(set (match_operand:SI 0 "general_operand" "=r") - (mult:SI (match_operand:SI 1 "general_operand" "%0") - (match_operand:SI 2 "general_operand" "r")))] - "GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80" - "* return AS2 (imul%L0,%2,%0);") +}" + [(set_attr "type" "imul")]) (define_insn "mulsi3" - [(set (match_operand:SI 0 "general_operand" "=r,r") - (mult:SI (match_operand:SI 1 "general_operand" "%0,rm") + [(set (match_operand:SI 0 "register_operand" "=r,r") + (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,rm") (match_operand:SI 2 "general_operand" "g,i")))] "" "* @@ -2793,35 +3325,40 @@ /* Assembler has weird restrictions. */ return AS2 (imul%L0,%2,%0); return AS3 (imul%L0,%2,%1,%0); -}") +}" + [(set_attr "type" "imul")]) (define_insn "umulqihi3" - [(set (match_operand:HI 0 "general_operand" "=a") - (mult:HI (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0")) + [(set (match_operand:HI 0 "register_operand" "=a") + (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%0")) (zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))] "" - "mul%B0 %2") + "mul%B0 %2" + [(set_attr "type" "imul")]) (define_insn "mulqihi3" - [(set (match_operand:HI 0 "general_operand" "=a") - (mult:HI (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0")) + [(set (match_operand:HI 0 "register_operand" "=a") + (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0")) (sign_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))] "" - "imul%B0 %2") + "imul%B0 %2" + [(set_attr "type" "imul")]) (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") + "mul%L0 %2" + [(set_attr "type" "imul")]) (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") + "imul%L0 %2" + [(set_attr "type" "imul")]) (define_insn "umulsi3_highpart" [(set (match_operand:SI 0 "register_operand" "=d") @@ -2830,7 +3367,8 @@ (const_int 32)))) (clobber (match_scratch:SI 3 "=a"))] "TARGET_WIDE_MULTIPLY" - "mul%L0 %2") + "mul%L0 %2" + [(set_attr "type" "imul")]) (define_insn "smulsi3_highpart" [(set (match_operand:SI 0 "register_operand" "=d") @@ -2839,27 +3377,28 @@ (const_int 32)))) (clobber (match_scratch:SI 3 "=a"))] "TARGET_WIDE_MULTIPLY" - "imul%L0 %2") + "imul%L0 %2" + [(set_attr "type" "imul")]) ;; 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" "")))] + (mult:XF (match_operand:XF 1 "register_operand" "") + (match_operand:XF 2 "register_operand" "")))] "TARGET_80387" "") (define_expand "muldf3" [(set (match_operand:DF 0 "register_operand" "") - (mult:DF (match_operand:DF 1 "nonimmediate_operand" "") + (mult:DF (match_operand:DF 1 "register_operand" "") (match_operand:DF 2 "nonimmediate_operand" "")))] "TARGET_80387" "") (define_expand "mulsf3" [(set (match_operand:SF 0 "register_operand" "") - (mult:SF (match_operand:SF 1 "nonimmediate_operand" "") + (mult:SF (match_operand:SF 1 "register_operand" "") (match_operand:SF 2 "nonimmediate_operand" "")))] "TARGET_80387" "") @@ -2867,38 +3406,39 @@ ;;- divide instructions (define_insn "divqi3" - [(set (match_operand:QI 0 "general_operand" "=a") - (div:QI (match_operand:HI 1 "general_operand" "0") - (match_operand:QI 2 "general_operand" "qm")))] + [(set (match_operand:QI 0 "register_operand" "=a") + (div:QI (match_operand:HI 1 "register_operand" "0") + (match_operand:QI 2 "nonimmediate_operand" "qm")))] "" "idiv%B0 %2") (define_insn "udivqi3" - [(set (match_operand:QI 0 "general_operand" "=a") - (udiv:QI (match_operand:HI 1 "general_operand" "0") - (match_operand:QI 2 "general_operand" "qm")))] + [(set (match_operand:QI 0 "register_operand" "=a") + (udiv:QI (match_operand:HI 1 "register_operand" "0") + (match_operand:QI 2 "nonimmediate_operand" "qm")))] "" - "div%B0 %2") + "div%B0 %2" + [(set_attr "type" "idiv")]) ;; 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" "")))] + (div:XF (match_operand:XF 1 "register_operand" "") + (match_operand:XF 2 "register_operand" "")))] "TARGET_80387" "") (define_expand "divdf3" [(set (match_operand:DF 0 "register_operand" "") - (div:DF (match_operand:DF 1 "nonimmediate_operand" "") - (match_operand:DF 2 "nonimmediate_operand" "")))] - "TARGET_80387" - "") - + (div:DF (match_operand:DF 1 "register_operand" "") + (match_operand:DF 2 "nonimmediate_operand" "")))] + "TARGET_80387" + "") + (define_expand "divsf3" [(set (match_operand:SF 0 "register_operand" "") - (div:SF (match_operand:SF 1 "nonimmediate_operand" "") + (div:SF (match_operand:SF 1 "register_operand" "") (match_operand:SF 2 "nonimmediate_operand" "")))] "TARGET_80387" "") @@ -2908,7 +3448,7 @@ (define_insn "divmodsi4" [(set (match_operand:SI 0 "register_operand" "=a") (div:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "general_operand" "rm"))) + (match_operand:SI 2 "nonimmediate_operand" "rm"))) (set (match_operand:SI 3 "register_operand" "=&d") (mod:SI (match_dup 1) (match_dup 2)))] "" @@ -2920,22 +3460,24 @@ output_asm_insn (\"cltd\", operands); #endif return AS1 (idiv%L0,%2); -}") +}" + [(set_attr "type" "idiv")]) (define_insn "divmodhi4" [(set (match_operand:HI 0 "register_operand" "=a") (div:HI (match_operand:HI 1 "register_operand" "0") - (match_operand:HI 2 "general_operand" "rm"))) + (match_operand:HI 2 "nonimmediate_operand" "rm"))) (set (match_operand:HI 3 "register_operand" "=&d") (mod:HI (match_dup 1) (match_dup 2)))] "" - "cwtd\;idiv%W0 %2") + "cwtd\;idiv%W0 %2" + [(set_attr "type" "idiv")]) ;; ??? Can we make gcc zero extend operand[0]? (define_insn "udivmodsi4" [(set (match_operand:SI 0 "register_operand" "=a") (udiv:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "general_operand" "rm"))) + (match_operand:SI 2 "nonimmediate_operand" "rm"))) (set (match_operand:SI 3 "register_operand" "=&d") (umod:SI (match_dup 1) (match_dup 2)))] "" @@ -2943,13 +3485,14 @@ { output_asm_insn (AS2 (xor%L3,%3,%3), operands); return AS1 (div%L0,%2); -}") +}" + [(set_attr "type" "idiv")]) ;; ??? Can we make gcc zero extend operand[0]? (define_insn "udivmodhi4" [(set (match_operand:HI 0 "register_operand" "=a") (udiv:HI (match_operand:HI 1 "register_operand" "0") - (match_operand:HI 2 "general_operand" "rm"))) + (match_operand:HI 2 "nonimmediate_operand" "rm"))) (set (match_operand:HI 3 "register_operand" "=&d") (umod:HI (match_dup 1) (match_dup 2)))] "" @@ -2957,7 +3500,8 @@ { output_asm_insn (AS2 (xor%W0,%3,%3), operands); return AS1 (div%W0,%2); -}") +}" + [(set_attr "type" "idiv")]) /* ;;this should be a valid double division which we may want to add @@ -2965,11 +3509,12 @@ (define_insn "" [(set (match_operand:SI 0 "register_operand" "=a") (udiv:DI (match_operand:DI 1 "register_operand" "a") - (match_operand:SI 2 "general_operand" "rm"))) + (match_operand:SI 2 "nonimmediate_operand" "rm"))) (set (match_operand:SI 3 "register_operand" "=d") (umod:SI (match_dup 1) (match_dup 2)))] "" - "div%L0 %2,%0") + "div%L0 %2,%0" + [(set_attr "type" "idiv")]) */ ;;- and instructions @@ -2989,21 +3534,33 @@ ;; The `r' in `rm' for operand 3 looks redundant, but it causes ;; optional reloads to be generated if op 3 is a pseudo in a stack slot. -;; ??? What if we only change one byte of an offsettable memory reference? (define_insn "andsi3" - [(set (match_operand:SI 0 "general_operand" "=r,r,rm,r") - (and:SI (match_operand:SI 1 "general_operand" "%rm,qm,0,0") - (match_operand:SI 2 "general_operand" "L,K,ri,rm")))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "ri,rm")))] "" "* { - if (GET_CODE (operands[2]) == CONST_INT - && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) + HOST_WIDE_INT intval; + if (!rtx_equal_p (operands[0], operands[1]) + && rtx_equal_p (operands[0], operands[2])) { - if (INTVAL (operands[2]) == 0xffff && REG_P (operands[0]) + rtx tmp; + tmp = operands[1]; + operands[1] = operands[2]; + operands[2] = tmp; + } + switch (GET_CODE (operands[2])) + { + case CONST_INT: + if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + break; + intval = INTVAL (operands[2]); + /* zero-extend 16->32? */ + if (intval == 0xffff && REG_P (operands[0]) && (! REG_P (operands[1]) || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0) - && (TARGET_386 || ! rtx_equal_p (operands[0], operands[1]))) + && (!TARGET_ZERO_EXTEND_WITH_AND || ! rtx_equal_p (operands[0], operands[1]))) { /* ??? tege: Should forget CC_STATUS only if we clobber a remembered operand. Fix that later. */ @@ -3015,11 +3572,12 @@ #endif } - if (INTVAL (operands[2]) == 0xff && REG_P (operands[0]) + /* zero extend 8->32? */ + if (intval == 0xff && REG_P (operands[0]) && !(REG_P (operands[1]) && NON_QI_REG_P (operands[1])) && (! REG_P (operands[1]) || REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0) - && (TARGET_386 || ! rtx_equal_p (operands[0], operands[1]))) + && (!TARGET_ZERO_EXTEND_WITH_AND || ! rtx_equal_p (operands[0], operands[1]))) { /* ??? tege: Should forget CC_STATUS only if we clobber a remembered operand. Fix that later. */ @@ -3031,47 +3589,110 @@ #endif } - if (QI_REG_P (operands[0]) && ~(INTVAL (operands[2]) | 0xff) == 0) - { - CC_STATUS_INIT; + /* Check partial bytes.. non-QI-regs are not available */ + if (REG_P (operands[0]) && ! QI_REG_P (operands[0])) + break; - if (INTVAL (operands[2]) == 0xffffff00) + /* only low byte has zero bits? */ + if (~(intval | 0xff) == 0) + { + intval &= 0xff; + if (REG_P (operands[0])) { - operands[2] = const0_rtx; - return AS2 (mov%B0,%2,%b0); + if (intval == 0) + { + CC_STATUS_INIT; + return AS2 (xor%B0,%b0,%b0); + } + + /* we're better off with the 32-bit version if reg != EAX */ + /* the value is sign-extended in 8 bits */ + if (REGNO (operands[0]) != 0 && (intval & 0x80)) + break; } - operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff); + CC_STATUS_INIT; + + operands[2] = GEN_INT (intval); + + if (intval == 0) + return AS2 (mov%B0,%2,%b0); + return AS2 (and%B0,%2,%b0); } - if (QI_REG_P (operands[0]) && ~(INTVAL (operands[2]) | 0xff00) == 0) + /* only second byte has zero? */ + if (~(intval | 0xff00) == 0) { CC_STATUS_INIT; - if (INTVAL (operands[2]) == 0xffff00ff) + intval = (intval >> 8) & 0xff; + operands[2] = GEN_INT (intval); + if (intval == 0) { - operands[2] = const0_rtx; - return AS2 (mov%B0,%2,%h0); + if (REG_P (operands[0])) + return AS2 (xor%B0,%h0,%h0); + operands[0] = adj_offsettable_operand (operands[0], 1); + return AS2 (mov%B0,%2,%b0); } - operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff); - return AS2 (and%B0,%2,%h0); + if (REG_P (operands[0])) + return AS2 (and%B0,%2,%h0); + + operands[0] = adj_offsettable_operand (operands[0], 1); + return AS2 (and%B0,%2,%b0); + } + + if (REG_P (operands[0])) + break; + + /* third byte has zero bits? */ + if (~(intval | 0xff0000) == 0) + { + intval = (intval >> 16) & 0xff; + operands[0] = adj_offsettable_operand (operands[0], 2); +byte_and_operation: + CC_STATUS_INIT; + operands[2] = GEN_INT (intval); + if (intval == 0) + return AS2 (mov%B0,%2,%b0); + return AS2 (and%B0,%2,%b0); + } + + /* fourth byte has zero bits? */ + if (~(intval | 0xff000000) == 0) + { + intval = (intval >> 24) & 0xff; + operands[0] = adj_offsettable_operand (operands[0], 3); + goto byte_and_operation; } - if (GET_CODE (operands[0]) == MEM && INTVAL (operands[2]) == 0xffff0000) + /* Low word is zero? */ + if (intval == 0xffff0000) { +word_zero_and_operation: + CC_STATUS_INIT; operands[2] = const0_rtx; return AS2 (mov%W0,%2,%w0); } + + /* High word is zero? */ + if (intval == 0x0000ffff) + { + operands[0] = adj_offsettable_operand (operands[0], 2); + goto word_zero_and_operation; + } + + default: + break; } return AS2 (and%L0,%2,%0); }") (define_insn "andhi3" - [(set (match_operand:HI 0 "general_operand" "=rm,r") - (and:HI (match_operand:HI 1 "general_operand" "%0,0") + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") (match_operand:HI 2 "general_operand" "ri,rm")))] "" "* @@ -3110,14 +3731,46 @@ operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff); return AS2 (and%B0,%2,%h0); } + + /* use 32-bit ops on registers when there are no sign issues.. */ + if (REG_P (operands[0])) + { + if (!(INTVAL (operands[2]) & ~0x7fff)) + return AS2 (and%L0,%2,%k0); + } + } + + if (REG_P (operands[0]) + && i386_aligned_p (operands[2])) + { + CC_STATUS_INIT; + /* If op[2] is constant, we should zero-extend it and */ + /* make a note that op[0] has been zero-extended, so */ + /* that we could use 32-bit ops on it forthwith, but */ + /* there is no such reg-note available. Instead we do */ + /* a sign extension as that can result in shorter asm */ + operands[2] = i386_sext16_if_const (operands[2]); + return AS2 (and%L0,%k2,%k0); + } + + /* Use a 32-bit word with the upper bits set, invalidate CC */ + if (GET_CODE (operands[2]) == CONST_INT + && i386_aligned_p (operands[0])) + { + HOST_WIDE_INT val = INTVAL (operands[2]); + CC_STATUS_INIT; + val |= ~0xffff; + if (val != INTVAL (operands[2])) + operands[2] = GEN_INT (val); + return AS2 (and%L0,%k2,%k0); } return AS2 (and%W0,%2,%0); }") (define_insn "andqi3" - [(set (match_operand:QI 0 "general_operand" "=qm,q") - (and:QI (match_operand:QI 1 "general_operand" "%0,0") + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") + (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") (match_operand:QI 2 "general_operand" "qn,qmn")))] "" "* return AS2 (and%B0,%2,%0);") @@ -3136,10 +3789,10 @@ "and%W0 %1,%0") (define_insn "" - [(set (match_operand:SI 0 "general_operand" "=q") + [(set (match_operand:SI 0 "register_operand" "=q") (and:SI (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")) - (match_operand:SI 2 "general_operand" "0")))] + (match_operand:SI 2 "register_operand" "0")))] "GET_CODE (operands[2]) == CONST_INT && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))" "and%L0 %1,%0") @@ -3148,134 +3801,278 @@ ;;- Bit set (inclusive or) instructions -;; ??? What if we only change one byte of an offsettable memory reference? +;; This optimizes known byte-wide operations to memory, and in some cases +;; to QI registers.. Note that we don't want to use the QI registers too +;; aggressively, because often the 32-bit register instruction is the same +;; size, and likely to be faster on PentiumPro. (define_insn "iorsi3" - [(set (match_operand:SI 0 "general_operand" "=rm,r") - (ior:SI (match_operand:SI 1 "general_operand" "%0,0") + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") (match_operand:SI 2 "general_operand" "ri,rm")))] "" "* { - if (GET_CODE (operands[2]) == CONST_INT - && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) + HOST_WIDE_INT intval; + switch (GET_CODE (operands[2])) { - if ((! REG_P (operands[0]) || QI_REG_P (operands[0])) - && (INTVAL (operands[2]) & ~0xff) == 0) - { - CC_STATUS_INIT; + case CONST_INT: - if (INTVAL (operands[2]) == 0xff) - return AS2 (mov%B0,%2,%b0); + if (REG_P (operands[0]) && ! QI_REG_P (operands[0])) + break; - return AS2 (or%B0,%2,%b0); + /* don't try to optimize volatile accesses */ + if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + break; + + intval = INTVAL (operands[2]); + if ((intval & ~0xff) == 0) + { + if (REG_P (operands[0])) + { + /* Do low byte access only for %eax or when high bit is set */ + if (REGNO (operands[0]) != 0 && !(intval & 0x80)) + break; + } + +byte_or_operation: + CC_STATUS_INIT; + + if (intval != INTVAL (operands[2])) + operands[2] = GEN_INT (intval); + + if (intval == 0xff) + return AS2 (mov%B0,%2,%b0); + + return AS2 (or%B0,%2,%b0); } - if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff00) == 0) + /* second byte? */ + if ((intval & ~0xff00) == 0) { - CC_STATUS_INIT; - operands[2] = GEN_INT (INTVAL (operands[2]) >> 8); + intval >>= 8; - if (INTVAL (operands[2]) == 0xff) - return AS2 (mov%B0,%2,%h0); + if (REG_P (operands[0])) + { + CC_STATUS_INIT; + operands[2] = GEN_INT (intval); + if (intval == 0xff) + return AS2 (mov%B0,%2,%h0); - return AS2 (or%B0,%2,%h0); + return AS2 (or%B0,%2,%h0); + } + + operands[0] = adj_offsettable_operand (operands[0], 1); + goto byte_or_operation; + } + + if (REG_P (operands[0])) + break; + + /* third byte? */ + if ((intval & ~0xff0000) == 0) + { + intval >>= 16; + operands[0] = adj_offsettable_operand (operands[0], 2); + goto byte_or_operation; + } + + /* fourth byte? */ + if ((intval & ~0xff000000) == 0) + { + intval = (intval >> 24) & 0xff; + operands[0] = adj_offsettable_operand (operands[0], 3); + goto byte_or_operation; } + + default: + break; } return AS2 (or%L0,%2,%0); }") (define_insn "iorhi3" - [(set (match_operand:HI 0 "general_operand" "=rm,r") - (ior:HI (match_operand:HI 1 "general_operand" "%0,0") + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") (match_operand:HI 2 "general_operand" "ri,rm")))] "" "* { - if (GET_CODE (operands[2]) == CONST_INT - && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) + HOST_WIDE_INT intval; + switch (GET_CODE (operands[2])) { - /* Can we ignore the upper byte? */ - if ((! REG_P (operands[0]) || QI_REG_P (operands[0])) - && (INTVAL (operands[2]) & 0xff00) == 0) - { - CC_STATUS_INIT; - if (INTVAL (operands[2]) & 0xffff0000) - operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff); + case CONST_INT: - if (INTVAL (operands[2]) == 0xff) - return AS2 (mov%B0,%2,%b0); + if (REG_P (operands[0]) && ! QI_REG_P (operands[0])) + break; + + /* don't try to optimize volatile accesses */ + if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + break; + + intval = 0xffff & INTVAL (operands[2]); - return AS2 (or%B0,%2,%b0); + if ((intval & 0xff00) == 0) + { + if (REG_P (operands[0])) + { + /* Do low byte access only for %eax or when high bit is set */ + if (REGNO (operands[0]) != 0 && !(intval & 0x80)) + break; + } + +byte_or_operation: + CC_STATUS_INIT; + + if (intval == 0xff) + return AS2 (mov%B0,%2,%b0); + + return AS2 (or%B0,%2,%b0); } - /* Can we ignore the lower byte? */ - /* ??? what about offsettable memory references? */ - if (QI_REG_P (operands[0]) - && (INTVAL (operands[2]) & 0xff) == 0) + /* high byte? */ + if ((intval & 0xff) == 0) { - CC_STATUS_INIT; - operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff); + intval >>= 8; + operands[2] = GEN_INT (intval); - if (INTVAL (operands[2]) == 0xff) - return AS2 (mov%B0,%2,%h0); + if (REG_P (operands[0])) + { + CC_STATUS_INIT; + if (intval == 0xff) + return AS2 (mov%B0,%2,%h0); + + return AS2 (or%B0,%2,%h0); + } - return AS2 (or%B0,%2,%h0); + operands[0] = adj_offsettable_operand (operands[0], 1); + + goto byte_or_operation; } + + default: + break; + } + + if (REG_P (operands[0]) + && i386_aligned_p (operands[2])) + { + CC_STATUS_INIT; + operands[2] = i386_sext16_if_const (operands[2]); + return AS2 (or%L0,%k2,%k0); + } + + if (GET_CODE (operands[2]) == CONST_INT + && i386_aligned_p (operands[0])) + { + CC_STATUS_INIT; + intval = 0xffff & INTVAL (operands[2]); + if (intval != INTVAL (operands[2])) + operands[2] = GEN_INT (intval); + return AS2 (or%L0,%2,%k0); } return AS2 (or%W0,%2,%0); }") (define_insn "iorqi3" - [(set (match_operand:QI 0 "general_operand" "=qm,q") - (ior:QI (match_operand:QI 1 "general_operand" "%0,0") + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") + (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") (match_operand:QI 2 "general_operand" "qn,qmn")))] "" "* return AS2 (or%B0,%2,%0);") ;;- xor instructions -;; ??? What if we only change one byte of an offsettable memory reference? (define_insn "xorsi3" - [(set (match_operand:SI 0 "general_operand" "=rm,r") - (xor:SI (match_operand:SI 1 "general_operand" "%0,0") + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") + (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") (match_operand:SI 2 "general_operand" "ri,rm")))] "" "* { - if (GET_CODE (operands[2]) == CONST_INT - && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) + HOST_WIDE_INT intval; + switch (GET_CODE (operands[2])) { - if ((! REG_P (operands[0]) || QI_REG_P (operands[0])) - && (INTVAL (operands[2]) & ~0xff) == 0) - { - CC_STATUS_INIT; + case CONST_INT: - if (INTVAL (operands[2]) == 0xff) - return AS1 (not%B0,%b0); + if (REG_P (operands[0]) && ! QI_REG_P (operands[0])) + break; - return AS2 (xor%B0,%2,%b0); + /* don't try to optimize volatile accesses */ + if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + break; + + intval = INTVAL (operands[2]); + if ((intval & ~0xff) == 0) + { + if (REG_P (operands[0])) + { + /* Do low byte access only for %eax or when high bit is set */ + if (REGNO (operands[0]) != 0 && !(intval & 0x80)) + break; + } + +byte_xor_operation: + CC_STATUS_INIT; + + if (intval == 0xff) + return AS1 (not%B0,%b0); + + if (intval != INTVAL (operands[2])) + operands[2] = GEN_INT (intval); + return AS2 (xor%B0,%2,%b0); } - if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff00) == 0) + /* second byte? */ + if ((intval & ~0xff00) == 0) { - CC_STATUS_INIT; - operands[2] = GEN_INT (INTVAL (operands[2]) >> 8); + intval >>= 8; - if (INTVAL (operands[2]) == 0xff) - return AS1 (not%B0,%h0); + if (REG_P (operands[0])) + { + CC_STATUS_INIT; + if (intval == 0xff) + return AS1 (not%B0,%h0); - return AS2 (xor%B0,%2,%h0); + operands[2] = GEN_INT (intval); + return AS2 (xor%B0,%2,%h0); + } + + operands[0] = adj_offsettable_operand (operands[0], 1); + + goto byte_xor_operation; } + + if (REG_P (operands[0])) + break; + + /* third byte? */ + if ((intval & ~0xff0000) == 0) + { + intval >>= 16; + operands[0] = adj_offsettable_operand (operands[0], 2); + goto byte_xor_operation; + } + + /* fourth byte? */ + if ((intval & ~0xff000000) == 0) + { + intval = (intval >> 24) & 0xff; + operands[0] = adj_offsettable_operand (operands[0], 3); + goto byte_xor_operation; + } + + default: + break; } return AS2 (xor%L0,%2,%0); }") (define_insn "xorhi3" - [(set (match_operand:HI 0 "general_operand" "=rm,r") - (xor:HI (match_operand:HI 1 "general_operand" "%0,0") + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") (match_operand:HI 2 "general_operand" "ri,rm")))] "" "* @@ -3312,16 +4109,136 @@ } } + if (REG_P (operands[0]) + && i386_aligned_p (operands[2])) + { + CC_STATUS_INIT; + operands[2] = i386_sext16_if_const (operands[2]); + return AS2 (xor%L0,%k2,%k0); + } + + if (GET_CODE (operands[2]) == CONST_INT + && i386_aligned_p (operands[0])) + { + HOST_WIDE_INT intval; + CC_STATUS_INIT; + intval = 0xffff & INTVAL (operands[2]); + if (intval != INTVAL (operands[2])) + operands[2] = GEN_INT (intval); + return AS2 (xor%L0,%2,%k0); + } + return AS2 (xor%W0,%2,%0); }") (define_insn "xorqi3" - [(set (match_operand:QI 0 "general_operand" "=qm,q") - (xor:QI (match_operand:QI 1 "general_operand" "%0,0") + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") + (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") (match_operand:QI 2 "general_operand" "qn,qm")))] "" "* return AS2 (xor%B0,%2,%0);") +;; logical operations for DImode + + +(define_insn "anddi3" + [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o") + (and:DI (match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o") + (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o"))) + (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))] + "" + "#") + +(define_insn "iordi3" + [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o") + (ior:DI (match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o") + (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o"))) + (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))] + "" + "#") + +(define_insn "xordi3" + [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o") + (xor:DI (match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o") + (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o"))) + (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))] + "" + "#") + +(define_split + [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o") + (match_operator:DI 4 "ix86_logical_operator" + [(match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o") + (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o")])) + (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))] + "reload_completed" + [(const_int 0)] + " +{ + rtx low[3], high[3], xops[7], temp; + rtx (*genfunc)() = (GET_CODE (operands[4]) == AND ? gen_andsi3 + : GET_CODE (operands[4]) == IOR ? gen_iorsi3 + : GET_CODE (operands[4]) == XOR ? gen_xorsi3 + : 0); + + 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) + { + emit_insn (gen_movsi (xops[1], xops[3])); + emit_insn (gen_movsi (xops[0], xops[2])); + } + else + { + xops[4] = high[2]; + xops[5] = low[2]; + xops[6] = operands[3]; + emit_insn (gen_movsi (xops[6], xops[3])); + emit_insn ((*genfunc) (xops[6], xops[6], xops[5])); + emit_insn (gen_movsi (xops[1], xops[6])); + emit_insn (gen_movsi (xops[6], xops[2])); + emit_insn ((*genfunc) (xops[6], xops[6], xops[4])); + emit_insn (gen_movsi (xops[0], xops[6])); + DONE; + } + } + + 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]; + + emit_insn (gen_movsi (xops[4], xops[3])); + emit_insn ((*genfunc) (xops[1], xops[1], xops[4])); + emit_insn (gen_movsi (xops[4], xops[2])); + emit_insn ((*genfunc) (xops[0], xops[0], xops[4])); + } + + else + { + emit_insn ((*genfunc) (low[0], low[0], low[2])); + emit_insn ((*genfunc) (high[0], high[0], high[2])); + } + + DONE; +}") + ;;- negation instructions (define_insn "negdi2" @@ -3345,50 +4262,50 @@ }") (define_insn "negsi2" - [(set (match_operand:SI 0 "general_operand" "=rm") - (neg:SI (match_operand:SI 1 "general_operand" "0")))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")))] "" "neg%L0 %0") (define_insn "neghi2" - [(set (match_operand:HI 0 "general_operand" "=rm") - (neg:HI (match_operand:HI 1 "general_operand" "0")))] + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")))] "" "neg%W0 %0") (define_insn "negqi2" - [(set (match_operand:QI 0 "general_operand" "=qm") - (neg:QI (match_operand:QI 1 "general_operand" "0")))] + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")))] "" "neg%B0 %0") (define_insn "negsf2" [(set (match_operand:SF 0 "register_operand" "=f") - (neg:SF (match_operand:SF 1 "general_operand" "0")))] + (neg:SF (match_operand:SF 1 "register_operand" "0")))] "TARGET_80387" "fchs") (define_insn "negdf2" [(set (match_operand:DF 0 "register_operand" "=f") - (neg:DF (match_operand:DF 1 "general_operand" "0")))] + (neg:DF (match_operand:DF 1 "register_operand" "0")))] "TARGET_80387" "fchs") (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") - (neg:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))] + (neg:DF (float_extend:DF (match_operand:SF 1 "register_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")))] + (neg:XF (match_operand:XF 1 "register_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"))))] + (neg:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))] "TARGET_80387" "fchs") @@ -3396,44 +4313,48 @@ (define_insn "abssf2" [(set (match_operand:SF 0 "register_operand" "=f") - (abs:SF (match_operand:SF 1 "general_operand" "0")))] + (abs:SF (match_operand:SF 1 "register_operand" "0")))] "TARGET_80387" - "fabs") + "fabs" + [(set_attr "type" "fpop")]) (define_insn "absdf2" [(set (match_operand:DF 0 "register_operand" "=f") - (abs:DF (match_operand:DF 1 "general_operand" "0")))] + (abs:DF (match_operand:DF 1 "register_operand" "0")))] "TARGET_80387" - "fabs") + "fabs" + [(set_attr "type" "fpop")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") - (abs:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))] + (abs:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))] "TARGET_80387" - "fabs") + "fabs" + [(set_attr "type" "fpop")]) (define_insn "absxf2" [(set (match_operand:XF 0 "register_operand" "=f") - (abs:XF (match_operand:XF 1 "general_operand" "0")))] + (abs:XF (match_operand:XF 1 "register_operand" "0")))] "TARGET_80387" - "fabs") + "fabs" + [(set_attr "type" "fpop")]) (define_insn "" [(set (match_operand:XF 0 "register_operand" "=f") - (abs:XF (float_extend:XF (match_operand:DF 1 "general_operand" "0"))))] + (abs:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))] "TARGET_80387" - "fabs") + "fabs" + [(set_attr "type" "fpop")]) (define_insn "sqrtsf2" [(set (match_operand:SF 0 "register_operand" "=f") - (sqrt:SF (match_operand:SF 1 "general_operand" "0")))] - "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 - && (TARGET_IEEE_FP || flag_fast_math) " + (sqrt:SF (match_operand:SF 1 "register_operand" "0")))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387" "fsqrt") (define_insn "sqrtdf2" [(set (match_operand:DF 0 "register_operand" "=f") - (sqrt:DF (match_operand:DF 1 "general_operand" "0")))] + (sqrt:DF (match_operand:DF 1 "register_operand" "0")))] "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math) " "fsqrt") @@ -3441,14 +4362,13 @@ (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (sqrt:DF (float_extend:DF - (match_operand:SF 1 "general_operand" "0"))))] - "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 - && (TARGET_IEEE_FP || flag_fast_math) " + (match_operand:SF 1 "register_operand" "0"))))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387" "fsqrt") (define_insn "sqrtxf2" [(set (match_operand:XF 0 "register_operand" "=f") - (sqrt:XF (match_operand:XF 1 "general_operand" "0")))] + (sqrt:XF (match_operand:XF 1 "register_operand" "0")))] "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math) " "fsqrt") @@ -3456,94 +4376,84 @@ (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) " + (match_operand:DF 1 "register_operand" "0"))))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387" "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) " + (match_operand:SF 1 "register_operand" "0"))))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387" "fsqrt") (define_insn "sindf2" [(set (match_operand:DF 0 "register_operand" "=f") (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))] - "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 - && (TARGET_IEEE_FP || flag_fast_math) " + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && 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_NO_FANCY_MATH_387 && TARGET_80387 - && (TARGET_IEEE_FP || flag_fast_math) " + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && 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_NO_FANCY_MATH_387 && TARGET_80387 - && (TARGET_IEEE_FP || flag_fast_math) " + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math" "fsin") (define_insn "sinxf2" [(set (match_operand:XF 0 "register_operand" "=f") (unspec:XF [(match_operand:XF 1 "register_operand" "0")] 1))] - "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 - && (TARGET_IEEE_FP || flag_fast_math) " + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && 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_NO_FANCY_MATH_387 && TARGET_80387 - && (TARGET_IEEE_FP || flag_fast_math) " + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && 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_NO_FANCY_MATH_387 && TARGET_80387 - && (TARGET_IEEE_FP || flag_fast_math) " + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && 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_NO_FANCY_MATH_387 && TARGET_80387 - && (TARGET_IEEE_FP || flag_fast_math) " + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math" "fcos") (define_insn "cosxf2" [(set (match_operand:XF 0 "register_operand" "=f") (unspec:XF [(match_operand:XF 1 "register_operand" "0")] 2))] - "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 - && (TARGET_IEEE_FP || flag_fast_math) " + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math" "fcos") ;;- one complement instructions (define_insn "one_cmplsi2" - [(set (match_operand:SI 0 "general_operand" "=rm") - (not:SI (match_operand:SI 1 "general_operand" "0")))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))] "" "not%L0 %0") (define_insn "one_cmplhi2" - [(set (match_operand:HI 0 "general_operand" "=rm") - (not:HI (match_operand:HI 1 "general_operand" "0")))] + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))] "" "not%W0 %0") (define_insn "one_cmplqi2" - [(set (match_operand:QI 0 "general_operand" "=qm") - (not:QI (match_operand:QI 1 "general_operand" "0")))] + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (not:QI (match_operand:QI 1 "nonimmediate_operand" "0")))] "" "not%B0 %0") @@ -3565,8 +4475,7 @@ ;; separately, making all shifts emit pairs of shift double and normal ;; shift. Since sh[lr]d does not shift more than 31 bits, and we wish to ;; support a 63 bit shift, each shift where the count is in a reg expands -;; to three pairs. If the overall shift is by N bits, then the first two -;; pairs shift by N / 2 and the last pair by N & 1. +;; to a pair of shifts, a branch, a shift by 32 and a label. ;; If the shift count is a constant, we need never emit more than one ;; shift pair, instead using moves and sign extension for counts greater @@ -3596,7 +4505,7 @@ [(set (match_operand:DI 0 "register_operand" "=&r") (ashift:DI (match_operand:DI 1 "register_operand" "0") (match_operand:QI 2 "const_int_operand" "J")))] - "" + "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')" "* { rtx xops[4], low[1], high[1]; @@ -3631,35 +4540,29 @@ (define_insn "ashldi3_non_const_int" [(set (match_operand:DI 0 "register_operand" "=&r") (ashift:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:QI 2 "register_operand" "c"))) - (clobber (match_dup 2))] + (match_operand:QI 2 "register_operand" "c")))] "" "* { - rtx xops[4], low[1], high[1]; + rtx xops[5], low[1], high[1]; CC_STATUS_INIT; split_di (operands, 1, low, high); xops[0] = operands[2]; - xops[1] = const1_rtx; + xops[1] = GEN_INT (32); xops[2] = low[0]; xops[3] = high[0]; - - output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */ + xops[4] = gen_label_rtx (); output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops); output_asm_insn (AS2 (sal%L2,%0,%2), xops); - output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops); - output_asm_insn (AS2 (sal%L2,%0,%2), xops); - - xops[1] = GEN_INT (7); /* shift count & 1 */ - - output_asm_insn (AS2 (shr%B0,%1,%0), xops); - - output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops); - output_asm_insn (AS2 (sal%L2,%0,%2), xops); - + output_asm_insn (AS2 (test%B0,%1,%b0), xops); + output_asm_insn (AS1 (je,%X4), xops); + output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */ + output_asm_insn (AS2 (xor%L2,%2,%2), xops); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (xops[4])); RET; }") @@ -3668,15 +4571,15 @@ ;; is smaller - use leal for now unless the shift count is 1. (define_insn "ashlsi3" - [(set (match_operand:SI 0 "general_operand" "=r,rm") - (ashift:SI (match_operand:SI 1 "general_operand" "r,0") + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "r,0") (match_operand:SI 2 "nonmemory_operand" "M,cI")))] "" "* { if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1])) { - if (!TARGET_386 && INTVAL (operands[2]) == 1) + if (TARGET_DOUBLE_WITH_ADD && INTVAL (operands[2]) == 1) { output_asm_insn (AS2 (mov%L0,%1,%0), operands); return AS2 (add%L0,%1,%0); @@ -3690,8 +4593,8 @@ output_asm_insn (AS2 (mov%L0,%1,%0), operands); operands[1] = operands[0]; } - operands[1] = gen_rtx (MULT, SImode, operands[1], - GEN_INT (1 << INTVAL (operands[2]))); + operands[1] = gen_rtx_MULT (SImode, operands[1], + GEN_INT (1 << INTVAL (operands[2]))); return AS2 (lea%L0,%a1,%0); } } @@ -3706,8 +4609,8 @@ }") (define_insn "ashlhi3" - [(set (match_operand:HI 0 "general_operand" "=rm") - (ashift:HI (match_operand:HI 1 "general_operand" "0") + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:HI 2 "nonmemory_operand" "cI")))] "" "* @@ -3722,8 +4625,8 @@ }") (define_insn "ashlqi3" - [(set (match_operand:QI 0 "general_operand" "=qm") - (ashift:QI (match_operand:QI 1 "general_operand" "0") + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "nonmemory_operand" "cI")))] "" "* @@ -3759,11 +4662,36 @@ DONE; }") +(define_insn "ashldi3_32" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,m") + (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r") + (const_int 32)))] + "" + "* +{ + rtx low[2], high[2], xops[4]; + + split_di (operands, 2, low, high); + xops[0] = high[0]; + xops[1] = low[1]; + xops[2] = low[0]; + xops[3] = const0_rtx; + if (!rtx_equal_p (xops[0], xops[1])) + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + + if (GET_CODE (low[0]) == MEM) + output_asm_insn (AS2 (mov%L2,%3,%2), xops); + else + output_asm_insn (AS2 (xor%L2,%2,%2), xops); + + RET; +}") + (define_insn "ashrdi3_const_int" [(set (match_operand:DI 0 "register_operand" "=&r") (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") (match_operand:QI 2 "const_int_operand" "J")))] - "" + "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')" "* { rtx xops[4], low[1], high[1]; @@ -3800,41 +4728,36 @@ (define_insn "ashrdi3_non_const_int" [(set (match_operand:DI 0 "register_operand" "=&r") (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:QI 2 "register_operand" "c"))) - (clobber (match_dup 2))] + (match_operand:QI 2 "register_operand" "c")))] "" "* { - rtx xops[4], low[1], high[1]; + rtx xops[5], low[1], high[1]; CC_STATUS_INIT; split_di (operands, 1, low, high); xops[0] = operands[2]; - xops[1] = const1_rtx; + xops[1] = GEN_INT (32); xops[2] = low[0]; xops[3] = high[0]; - - output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */ + xops[4] = gen_label_rtx (); output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops); output_asm_insn (AS2 (sar%L3,%0,%3), xops); - output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops); - output_asm_insn (AS2 (sar%L3,%0,%3), xops); - - xops[1] = GEN_INT (7); /* shift count & 1 */ - - output_asm_insn (AS2 (shr%B0,%1,%0), xops); - - output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops); - output_asm_insn (AS2 (sar%L3,%0,%3), xops); - + output_asm_insn (AS2 (test%B0,%1,%b0), xops); + output_asm_insn (AS1 (je,%X4), xops); + xops[1] = GEN_INT (31); + output_asm_insn (AS2 (mov%L2,%3,%2), xops); + output_asm_insn (AS2 (sar%L3,%1,%3), xops); /* shift by 32 */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (xops[4])); RET; }") (define_insn "ashrsi3" - [(set (match_operand:SI 0 "general_operand" "=rm") - (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:SI 2 "nonmemory_operand" "cI")))] "" "* @@ -3846,8 +4769,8 @@ }") (define_insn "ashrhi3" - [(set (match_operand:HI 0 "general_operand" "=rm") - (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:HI 2 "nonmemory_operand" "cI")))] "" "* @@ -3859,8 +4782,8 @@ }") (define_insn "ashrqi3" - [(set (match_operand:QI 0 "general_operand" "=qm") - (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "nonmemory_operand" "cI")))] "" "* @@ -3895,11 +4818,36 @@ DONE; }") +(define_insn "lshrdi3_32" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,m") + (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r") + (const_int 32)))] + "" + "* +{ + rtx low[2], high[2], xops[4]; + + split_di (operands, 2, low, high); + xops[0] = low[0]; + xops[1] = high[1]; + xops[2] = high[0]; + xops[3] = const0_rtx; + if (!rtx_equal_p (xops[0], xops[1])) + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + + if (GET_CODE (low[0]) == MEM) + output_asm_insn (AS2 (mov%L2,%3,%2), xops); + else + output_asm_insn (AS2 (xor%L2,%2,%2), xops); + + RET; +}") + (define_insn "lshrdi3_const_int" [(set (match_operand:DI 0 "register_operand" "=&r") (lshiftrt:DI (match_operand:DI 1 "register_operand" "0") (match_operand:QI 2 "const_int_operand" "J")))] - "" + "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')" "* { rtx xops[4], low[1], high[1]; @@ -3935,41 +4883,35 @@ (define_insn "lshrdi3_non_const_int" [(set (match_operand:DI 0 "register_operand" "=&r") (lshiftrt:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:QI 2 "register_operand" "c"))) - (clobber (match_dup 2))] + (match_operand:QI 2 "register_operand" "c")))] "" "* { - rtx xops[4], low[1], high[1]; + rtx xops[5], low[1], high[1]; CC_STATUS_INIT; split_di (operands, 1, low, high); xops[0] = operands[2]; - xops[1] = const1_rtx; + xops[1] = GEN_INT (32); xops[2] = low[0]; xops[3] = high[0]; - - output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */ - - output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops); - output_asm_insn (AS2 (shr%L3,%0,%3), xops); - output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops); - output_asm_insn (AS2 (shr%L3,%0,%3), xops); - - xops[1] = GEN_INT (7); /* shift count & 1 */ - - output_asm_insn (AS2 (shr%B0,%1,%0), xops); + xops[4] = gen_label_rtx (); output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops); output_asm_insn (AS2 (shr%L3,%0,%3), xops); - + output_asm_insn (AS2 (test%B0,%1,%b0), xops); + output_asm_insn (AS1 (je,%X4), xops); + output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */ + output_asm_insn (AS2 (xor%L3,%3,%3), xops); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (xops[4])); RET; }") (define_insn "lshrsi3" - [(set (match_operand:SI 0 "general_operand" "=rm") - (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:SI 2 "nonmemory_operand" "cI")))] "" "* @@ -3981,8 +4923,8 @@ }") (define_insn "lshrhi3" - [(set (match_operand:HI 0 "general_operand" "=rm") - (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:HI 2 "nonmemory_operand" "cI")))] "" "* @@ -3994,8 +4936,8 @@ }") (define_insn "lshrqi3" - [(set (match_operand:QI 0 "general_operand" "=qm") - (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "nonmemory_operand" "cI")))] "" "* @@ -4009,8 +4951,8 @@ ;;- rotate instructions (define_insn "rotlsi3" - [(set (match_operand:SI 0 "general_operand" "=rm") - (rotate:SI (match_operand:SI 1 "general_operand" "0") + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:SI 2 "nonmemory_operand" "cI")))] "" "* @@ -4022,8 +4964,8 @@ }") (define_insn "rotlhi3" - [(set (match_operand:HI 0 "general_operand" "=rm") - (rotate:HI (match_operand:HI 1 "general_operand" "0") + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:HI 2 "nonmemory_operand" "cI")))] "" "* @@ -4035,8 +4977,8 @@ }") (define_insn "rotlqi3" - [(set (match_operand:QI 0 "general_operand" "=qm") - (rotate:QI (match_operand:QI 1 "general_operand" "0") + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "nonmemory_operand" "cI")))] "" "* @@ -4048,8 +4990,8 @@ }") (define_insn "rotrsi3" - [(set (match_operand:SI 0 "general_operand" "=rm") - (rotatert:SI (match_operand:SI 1 "general_operand" "0") + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0") (match_operand:SI 2 "nonmemory_operand" "cI")))] "" "* @@ -4061,8 +5003,8 @@ }") (define_insn "rotrhi3" - [(set (match_operand:HI 0 "general_operand" "=rm") - (rotatert:HI (match_operand:HI 1 "general_operand" "0") + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0") (match_operand:HI 2 "nonmemory_operand" "cI")))] "" "* @@ -4074,8 +5016,8 @@ }") (define_insn "rotrqi3" - [(set (match_operand:QI 0 "general_operand" "=qm") - (rotatert:QI (match_operand:QI 1 "general_operand" "0") + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0") (match_operand:QI 2 "nonmemory_operand" "cI")))] "" "* @@ -4090,11 +5032,13 @@ ;; This usually looses. But try a define_expand to recognize a few case ;; we can do efficiently, such as accessing the "high" QImode registers, ;; %ah, %bh, %ch, %dh. +;; ??? Note this has a botch on the mode of operand 0, which needs to be +;; fixed if this is ever enabled. (define_insn "insv" [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+&r") - (match_operand:SI 1 "general_operand" "i") - (match_operand:SI 2 "general_operand" "i")) - (match_operand:SI 3 "general_operand" "ri"))] + (match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")) + (match_operand:SI 3 "nonmemory_operand" "ri"))] "" "* { @@ -4110,7 +5054,7 @@ } else { - operands[0] = gen_rtx (REG, SImode, REGNO (operands[0])); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0])); if (INTVAL (operands[2])) output_asm_insn (AS2 (ror%L0,%2,%0), operands); output_asm_insn (AS3 (shrd%L0,%1,%3,%0), operands); @@ -4130,7 +5074,7 @@ [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "") (match_operand:SI 1 "immediate_operand" "") (match_operand:SI 2 "immediate_operand" "")) - (match_operand:QI 3 "general_operand" "ri"))] + (match_operand:QI 3 "nonmemory_operand" "ri"))] "" " { @@ -4143,22 +5087,6 @@ && ! INTVAL (operands[1]) == 1) FAIL; }") - -;; ??? Are these constraints right? -(define_insn "" - [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+&qo") - (const_int 8) - (const_int 8)) - (match_operand:QI 1 "general_operand" "qn"))] - "" - "* -{ - if (REG_P (operands[0])) - return AS2 (mov%B0,%1,%h0); - - operands[0] = adj_offsettable_operand (operands[0], 1); - return AS2 (mov%B0,%1,%0); -}") */ ;; On i386, the register count for a bit operation is *not* truncated, @@ -4173,11 +5101,11 @@ ;; General bit set and clear. (define_insn "" - [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+rm") + [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+rm") (const_int 1) - (match_operand:SI 2 "general_operand" "r")) + (match_operand:SI 2 "register_operand" "r")) (match_operand:SI 3 "const_int_operand" "n"))] - "TARGET_386 && GET_CODE (operands[2]) != CONST_INT" + "TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT" "* { CC_STATUS_INIT; @@ -4191,11 +5119,11 @@ ;; Bit complement. See comments on previous pattern. ;; ??? Is this really worthwhile? (define_insn "" - [(set (match_operand:SI 0 "general_operand" "=rm") + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") (xor:SI (ashift:SI (const_int 1) - (match_operand:SI 1 "general_operand" "r")) - (match_operand:SI 2 "general_operand" "0")))] - "TARGET_386 && GET_CODE (operands[1]) != CONST_INT" + (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "nonimmediate_operand" "0")))] + "TARGET_USE_BIT_TEST && GET_CODE (operands[1]) != CONST_INT" "* { CC_STATUS_INIT; @@ -4204,11 +5132,11 @@ }") (define_insn "" - [(set (match_operand:SI 0 "general_operand" "=rm") - (xor:SI (match_operand:SI 1 "general_operand" "0") + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (xor:SI (match_operand:SI 1 "nonimmediate_operand" "0") (ashift:SI (const_int 1) - (match_operand:SI 2 "general_operand" "r"))))] - "TARGET_386 && GET_CODE (operands[2]) != CONST_INT" + (match_operand:SI 2 "register_operand" "r"))))] + "TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT" "* { CC_STATUS_INIT; @@ -4229,7 +5157,7 @@ (define_insn "" [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r") (const_int 1) - (match_operand:SI 1 "general_operand" "r")))] + (match_operand:SI 1 "register_operand" "r")))] "GET_CODE (operands[1]) != CONST_INT" "* { @@ -4272,7 +5200,7 @@ ;; The CPU may access unspecified bytes around the actual target byte. (define_insn "" - [(set (cc0) (zero_extract (match_operand:QI 0 "general_operand" "rm") + [(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "m") (match_operand:SI 1 "const_int_operand" "n") (match_operand:SI 2 "const_int_operand" "n")))] "GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0])" @@ -4403,7 +5331,8 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (sete,%0); OUTPUT_JUMP (\"setg %0\", \"seta %0\", NULL_PTR); @@ -4435,7 +5364,8 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (sete,%0); OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %0\"); @@ -4467,7 +5397,8 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (sete,%0); OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %0\"); @@ -4499,7 +5430,8 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (setb,%0); OUTPUT_JUMP (\"setle %0\", \"setbe %0\", NULL_PTR); @@ -4553,6 +5485,14 @@ if (cc_prev_status.flags & CC_Z_IN_NOT_C) return \"jnc %l0\"; else + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x4000); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (jne,%l0); + } + return \"je %l0\"; }") @@ -4585,6 +5525,14 @@ if (cc_prev_status.flags & CC_Z_IN_NOT_C) return \"jc %l0\"; else + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x4000); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (je,%l0); + } + return \"jne %l0\"; }") @@ -4607,9 +5555,17 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (je,%l0); + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x4100); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (je,%l0); + } OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", NULL_PTR); }") @@ -4651,9 +5607,17 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (je,%l0); + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x100); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (jne,%l0); + } OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\"); }") @@ -4695,9 +5659,16 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (je,%l0); - + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x100); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (je,%l0); + } OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\"); }") @@ -4739,8 +5710,16 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (jb,%l0); + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x4100); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (jne,%l0); + } OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", NULL_PTR); }") @@ -4778,6 +5757,13 @@ if (cc_prev_status.flags & CC_Z_IN_NOT_C) return \"jc %l0\"; else + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x4000); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (je,%l0); + } return \"jne %l0\"; }") @@ -4793,6 +5779,13 @@ if (cc_prev_status.flags & CC_Z_IN_NOT_C) return \"jnc %l0\"; else + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x4000); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (jne,%l0); + } return \"je %l0\"; }") @@ -4805,9 +5798,16 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (jne,%l0); - + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x4100); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (jne,%l0); + } OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", NULL_PTR); }") @@ -4829,8 +5829,16 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (jne,%l0); + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x100); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (je,%l0); + } OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\"); }") @@ -4853,9 +5861,16 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (jne,%l0); - + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x100); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (jne,%l0); + } OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\"); }") @@ -4877,9 +5892,17 @@ "" "* { - if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387) + && ! (cc_prev_status.flags & CC_FCOMI)) return AS1 (jae,%l0); + if (cc_prev_status.flags & CC_TEST_AX) + { + operands[1] = gen_rtx_REG (SImode, 0); + operands[2] = GEN_INT (0x4100); + output_asm_insn (AS2 (testl,%2,%1), operands); + return AS1 (je,%l0); + } OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", NULL_PTR); }") @@ -4901,7 +5924,7 @@ "jmp %l0") (define_insn "indirect_jump" - [(set (pc) (match_operand:SI 0 "general_operand" "rm"))] + [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))] "" "* { @@ -4929,7 +5952,7 @@ (define_insn "" [(set (pc) (if_then_else (match_operator 0 "arithmetic_comparison_operator" - [(plus:SI (match_operand:SI 1 "general_operand" "+r,m") + [(plus:SI (match_operand:SI 1 "nonimmediate_operand" "+r,m") (match_operand:SI 2 "general_operand" "rmi,ri")) (const_int 0)]) (label_ref (match_operand 3 "" "")) @@ -4944,7 +5967,7 @@ if (operands[2] == constm1_rtx) output_asm_insn (AS1 (dec%L1,%1), operands); - else if (operands[1] == const1_rtx) + else if (operands[2] == const1_rtx) output_asm_insn (AS1 (inc%L1,%1), operands); else @@ -4956,7 +5979,7 @@ (define_insn "" [(set (pc) (if_then_else (match_operator 0 "arithmetic_comparison_operator" - [(minus:SI (match_operand:SI 1 "general_operand" "+r,m") + [(minus:SI (match_operand:SI 1 "nonimmediate_operand" "+r,m") (match_operand:SI 2 "general_operand" "rmi,ri")) (const_int 0)]) (label_ref (match_operand 3 "" "")) @@ -4980,6 +6003,110 @@ return AS1 (%J0,%l3); }") +(define_insn "" + [(set (pc) + (if_then_else (ne (match_operand:SI 0 "general_operand" "+g") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; + operands[2] = const1_rtx; + output_asm_insn (AS2 (sub%L0,%2,%0), operands); + return \"jnc %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (eq (match_operand:SI 0 "general_operand" "+g") + (const_int 0)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; + operands[2] = const1_rtx; + output_asm_insn (AS2 (sub%L0,%2,%0), operands); + return \"jc %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; + output_asm_insn (AS1 (dec%L0,%0), operands); + return \"jnz %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (eq (match_operand:SI 0 "general_operand" "+g") + (const_int 1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1)))] + "" + "* +{ + CC_STATUS_INIT; + output_asm_insn (AS1 (dec%L0,%0), operands); + return \"jz %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (ne (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "" + "* +{ + CC_STATUS_INIT; + output_asm_insn (AS1 (inc%L0,%0), operands); + return \"jnz %l1\"; +}") + +(define_insn "" + [(set (pc) + (if_then_else (eq (match_operand:SI 0 "general_operand" "+g") + (const_int -1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int 1)))] + "" + "* +{ + CC_STATUS_INIT; + output_asm_insn (AS1 (inc%L0,%0), operands); + return \"jz %l1\"; +}") + ;; Implement switch statements when generating PIC code. Switches are ;; implemented by `tablejump' when not using -fpic. @@ -4987,10 +6114,12 @@ (define_expand "casesi" [(set (match_dup 5) - (minus:SI (match_operand:SI 0 "general_operand" "") + (match_operand:SI 0 "general_operand" "")) + (set (match_dup 6) + (minus:SI (match_dup 5) (match_operand:SI 1 "general_operand" ""))) (set (cc0) - (compare:CC (match_dup 5) + (compare:CC (match_dup 6) (match_operand:SI 2 "general_operand" ""))) (set (pc) (if_then_else (gtu (cc0) @@ -5000,14 +6129,15 @@ (parallel [(set (pc) (minus:SI (reg:SI 3) - (mem:SI (plus:SI (mult:SI (match_dup 5) + (mem:SI (plus:SI (mult:SI (match_dup 6) (const_int 4)) (label_ref (match_operand 3 "" "")))))) - (clobber (match_scratch:SI 6 ""))])] + (clobber (match_scratch:SI 7 ""))])] "flag_pic" " { operands[5] = gen_reg_rtx (SImode); + operands[6] = gen_reg_rtx (SImode); current_function_uses_pic_offset_table = 1; }") @@ -5061,12 +6191,12 @@ output_asm_insn (AS2 (mov%L2,%3,%2), xops); output_asm_insn (\"sub%L2 %l1@GOTOFF(%3,%0,4),%2\", xops); output_asm_insn (AS1 (jmp,%*%2), xops); - ASM_OUTPUT_ALIGN_CODE (asm_out_file); + ASM_OUTPUT_ALIGN (asm_out_file, i386_align_jumps); RET; }") (define_insn "tablejump" - [(set (pc) (match_operand:SI 0 "general_operand" "rm")) + [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm")) (use (label_ref (match_operand 1 "" "")))] "" "* @@ -5312,9 +6442,10 @@ coprocessor registers as containing a possible return value, simply pretend the untyped call returns a complex long double value. */ + emit_call_insn (TARGET_80387 - ? gen_call_value (gen_rtx (REG, XCmode, FIRST_FLOAT_REG), - operands[0], const0_rtx) + ? gen_call_value (gen_rtx_REG (XCmode, FIRST_FLOAT_REG), + operands[0], const0_rtx) : gen_call (operands[0], const0_rtx)); for (i = 0; i < XVECLEN (operands[2], 0); i++) @@ -5344,19 +6475,148 @@ ;; This is only done if the function's epilogue is known to be simple. ;; See comments for simple_386_epilogue in i386.c. -(define_insn "return" +(define_expand "return" [(return)] - "simple_386_epilogue ()" + "ix86_can_use_return_insn_p ()" + "") + +(define_insn "return_internal" + [(return)] + "reload_completed" + "ret") + +(define_insn "return_pop_internal" + [(return) + (use (match_operand:SI 0 "const_int_operand" ""))] + "reload_completed" + "ret %0") + +(define_insn "nop" + [(const_int 0)] + "" + "nop") + +(define_expand "prologue" + [(const_int 1)] + "" + " +{ + ix86_expand_prologue (); + DONE; +}") + +;; The use of UNSPEC here is currently not necessary - a simple SET of ebp +;; to itself would be enough. But this way we are safe even if some optimizer +;; becomes too clever in the future. +(define_insn "prologue_set_stack_ptr" + [(set (reg:SI 7) + (minus:SI (reg:SI 7) (match_operand:SI 0 "immediate_operand" "i"))) + (set (reg:SI 6) (unspec:SI [(reg:SI 6)] 4))] + "" "* { - function_epilogue (asm_out_file, get_frame_size ()); + rtx xops [2]; + + xops[0] = operands[0]; + xops[1] = stack_pointer_rtx; + output_asm_insn (AS2 (sub%L1,%0,%1), xops); RET; }") -(define_insn "nop" - [(const_int 0)] +(define_insn "prologue_set_got" + [(set (match_operand:SI 0 "" "") + (unspec_volatile + [(plus:SI (match_dup 0) + (plus:SI (match_operand:SI 1 "symbolic_operand" "") + (minus:SI (pc) (match_operand 2 "" ""))))] 1))] "" - "nop") + "* +{ + char buffer[64]; + + if (TARGET_DEEP_BRANCH_PREDICTION) + { + sprintf (buffer, \"addl %s,%%0\", XSTR (operands[1], 0)); + output_asm_insn (buffer, operands); + } + else + { + sprintf (buffer, \"addl %s+[.-%%X2],%%0\", XSTR (operands[1], 0)); + output_asm_insn (buffer, operands); + } + RET; +}") + +(define_insn "prologue_get_pc" + [(set (match_operand:SI 0 "" "") + (unspec_volatile [(plus:SI (pc) (match_operand 1 "" ""))] 2))] + "" + "* +{ + char buffer[64]; + + output_asm_insn (AS1 (call,%X1), operands); + if (! TARGET_DEEP_BRANCH_PREDICTION) + { + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (operands[1])); + } + RET; +}") + +(define_insn "prologue_get_pc_and_set_got" + [(unspec_volatile [(match_operand:SI 0 "" "")] 3)] + "" + "* +{ + operands[1] = gen_label_rtx (); + output_asm_insn (AS1 (call,%X1), operands); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", + CODE_LABEL_NUMBER (operands[1])); + output_asm_insn (AS1 (pop%L0,%0), operands); + output_asm_insn (\"addl $_GLOBAL_OFFSET_TABLE_+[.-%X1],%0\", operands); + RET; +}") + +(define_expand "epilogue" + [(const_int 1)] + "" + " +{ + ix86_expand_epilogue (); + DONE; +}") + +(define_insn "epilogue_set_stack_ptr" + [(set (reg:SI 7) (reg:SI 6)) + (clobber (reg:SI 6))] + "" + "* +{ + rtx xops [2]; + + xops[0] = frame_pointer_rtx; + xops[1] = stack_pointer_rtx; + output_asm_insn (AS2 (mov%L0,%0,%1), xops); + RET; +}") + +(define_insn "leave" + [(const_int 2) + (clobber (reg:SI 6)) + (clobber (reg:SI 7))] + "" + "leave") + +(define_insn "pop" + [(set (match_operand:SI 0 "register_operand" "r") + (mem:SI (reg:SI 7))) + (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))] + "" + "* +{ + output_asm_insn (AS1 (pop%L0,%P0), operands); + RET; +}") (define_expand "movstrsi" [(parallel [(set (match_operand:BLK 0 "memory_operand" "") @@ -5380,8 +6640,8 @@ operands[5] = addr0; operands[6] = addr1; - operands[0] = gen_rtx (MEM, BLKmode, addr0); - operands[1] = gen_rtx (MEM, BLKmode, addr1); + operands[0] = change_address (operands[0], VOIDmode, addr0); + operands[1] = change_address (operands[1], VOIDmode, addr1); }") ;; It might seem that operands 0 & 1 could use predicate register_operand. @@ -5426,6 +6686,73 @@ RET; }") +(define_expand "clrstrsi" + [(set (match_dup 3) (const_int 0)) + (parallel [(set (match_operand:BLK 0 "memory_operand" "") + (const_int 0)) + (use (match_operand:SI 1 "const_int_operand" "")) + (use (match_operand:SI 2 "const_int_operand" "")) + (use (match_dup 3)) + (clobber (match_scratch:SI 4 "")) + (clobber (match_dup 5))])] + "" + " +{ + rtx addr0, addr1; + + if (GET_CODE (operands[1]) != CONST_INT) + FAIL; + + addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + + operands[3] = gen_reg_rtx (SImode); + operands[5] = addr0; + + operands[0] = gen_rtx_MEM (BLKmode, addr0); +}") + +;; It might seem that operand 0 could use predicate register_operand. +;; But strength reduction might offset the MEM expression. So we let +;; reload put the address into %edi. + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "address_operand" "D")) + (const_int 0)) + (use (match_operand:SI 1 "const_int_operand" "n")) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "register_operand" "a")) + (clobber (match_scratch:SI 4 "=&c")) + (clobber (match_dup 0))] + "" + "* +{ + rtx xops[2]; + + output_asm_insn (\"cld\", operands); + if (GET_CODE (operands[1]) == CONST_INT) + { + if (INTVAL (operands[1]) & ~0x03) + { + xops[0] = GEN_INT ((INTVAL (operands[1]) >> 2) & 0x3fffffff); + xops[1] = operands[4]; + + output_asm_insn (AS2 (mov%L1,%0,%1), xops); +#ifdef INTEL_SYNTAX + output_asm_insn (\"rep stosd\", xops); +#else + output_asm_insn (\"rep\;stosl\", xops); +#endif + } + if (INTVAL (operands[1]) & 0x02) + output_asm_insn (\"stosw\", operands); + if (INTVAL (operands[1]) & 0x01) + output_asm_insn (\"stosb\", operands); + } + else + abort (); + RET; +}") + (define_expand "cmpstrsi" [(parallel [(set (match_operand:SI 0 "general_operand" "") (compare:SI (match_operand:BLK 1 "general_operand" "") @@ -5447,8 +6774,8 @@ operands[5] = addr1; operands[6] = addr2; - operands[1] = gen_rtx (MEM, BLKmode, addr1); - operands[2] = gen_rtx (MEM, BLKmode, addr2); + operands[1] = gen_rtx_MEM (BLKmode, addr1); + operands[2] = gen_rtx_MEM (BLKmode, addr2); }") @@ -5464,7 +6791,7 @@ ;; code to handle zero-length compares. (define_insn "" - [(set (match_operand:SI 0 "general_operand" "=&r") + [(set (match_operand:SI 0 "register_operand" "=&r") (compare:SI (mem:BLK (match_operand:SI 1 "address_operand" "S")) (mem:BLK (match_operand:SI 2 "address_operand" "D")))) (use (match_operand:SI 3 "register_operand" "c")) @@ -5475,7 +6802,7 @@ "" "* { - rtx xops[4], label; + rtx xops[2], label; label = gen_label_rtx (); @@ -5485,16 +6812,13 @@ output_asm_insn (\"je %l0\", &label); xops[0] = operands[0]; - xops[1] = gen_rtx (MEM, QImode, - gen_rtx (PLUS, SImode, operands[1], constm1_rtx)); - xops[2] = gen_rtx (MEM, QImode, - gen_rtx (PLUS, SImode, operands[2], constm1_rtx)); - xops[3] = operands[3]; - - output_asm_insn (AS2 (movz%B1%L0,%1,%0), xops); - output_asm_insn (AS2 (movz%B2%L3,%2,%3), xops); - - output_asm_insn (AS2 (sub%L0,%3,%0), xops); + xops[1] = const1_rtx; + output_asm_insn (AS2 (sbb%L0,%0,%0), xops); + if (QI_REG_P (xops[0])) + output_asm_insn (AS2 (or%B0,%1,%b0), xops); + else + output_asm_insn (AS2 (or%L0,%1,%0), xops); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (label)); RET; }") @@ -5515,7 +6839,7 @@ cc_status.flags |= CC_NOT_SIGNED; - xops[0] = gen_rtx (REG, QImode, 0); + xops[0] = gen_rtx_REG (QImode, 0); xops[1] = CONST0_RTX (QImode); output_asm_insn (\"cld\", operands); @@ -5523,101 +6847,64 @@ return \"repz\;cmps%B2\"; }") -(define_expand "ffssi2" - [(set (match_dup 2) - (plus:SI (ffs:SI (match_operand:SI 1 "general_operand" "")) - (const_int -1))) - (set (match_operand:SI 0 "general_operand" "") - (plus:SI (match_dup 2) (const_int 1)))] - "" - "operands[2] = gen_reg_rtx (SImode);") - + ;; Note, you cannot optimize away the branch following the bsfl by assuming ;; that the destination is not modified if the input is 0, since not all ;; x86 implementations do this. -(define_insn "" - [(set (match_operand:SI 0 "general_operand" "=&r") - (plus:SI (ffs:SI (match_operand:SI 1 "general_operand" "rm")) - (const_int -1)))] +(define_expand "ffssi2" + [(set (match_operand:SI 0 "general_operand" "") + (ffs:SI (match_operand:SI 1 "general_operand" "")))] "" - "* + " { - rtx xops[3]; - static int ffssi_label_number; - char buffer[30]; + rtx label = gen_label_rtx (), temp = gen_reg_rtx (SImode); - xops[0] = operands[0]; - xops[1] = operands[1]; - xops[2] = constm1_rtx; - 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); + emit_insn (gen_ffssi_1 (temp, operands[1])); + emit_cmp_insn (operands[1], const0_rtx, NE, NULL_RTX, SImode, 0, 0); + emit_jump_insn (gen_bne (label)); + emit_move_insn (temp, constm1_rtx); + emit_label (label); + temp = expand_binop (SImode, add_optab, temp, const1_rtx, + operands[0], 0, OPTAB_WIDEN); - ffssi_label_number++; - return \"\"; + if (temp != operands[0]) + emit_move_insn (operands[0], temp); + DONE; }") -(define_expand "ffshi2" - [(set (match_dup 2) - (plus:HI (ffs:HI (match_operand:HI 1 "general_operand" "")) - (const_int -1))) - (set (match_operand:HI 0 "general_operand" "") - (plus:HI (match_dup 2) (const_int 1)))] +(define_insn "ffssi_1" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "nonimmediate_operand" "rm")] 5))] "" - "operands[2] = gen_reg_rtx (HImode);") + "* return AS2 (bsf%L0,%1,%0);") -(define_insn "" - [(set (match_operand:HI 0 "general_operand" "=&r") - (plus:HI (ffs:HI (match_operand:SI 1 "general_operand" "rm")) - (const_int -1)))] +(define_expand "ffshi2" + [(set (match_operand:SI 0 "general_operand" "") + (ffs:HI (match_operand:HI 1 "general_operand" "")))] "" - "* + " { - rtx xops[3]; - static int ffshi_label_number; - char buffer[30]; + rtx label = gen_label_rtx (), temp = gen_reg_rtx (HImode); - xops[0] = operands[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); + emit_insn (gen_ffshi_1 (temp, operands[1])); + emit_cmp_insn (operands[1], const0_rtx, NE, NULL_RTX, HImode, 0, 0); + emit_jump_insn (gen_bne (label)); + emit_move_insn (temp, constm1_rtx); + emit_label (label); + temp = expand_binop (HImode, add_optab, temp, const1_rtx, + operands[0], 0, OPTAB_WIDEN); - ffshi_label_number++; - return \"\"; + if (temp != operands[0]) + emit_move_insn (operands[0], temp); + DONE; }") + +(define_insn "ffshi_1" + [(set (match_operand:HI 0 "register_operand" "=r") + (unspec:HI [(match_operand:SI 1 "nonimmediate_operand" "rm")] 5))] + "" + "* return AS2 (bsf%W0,%1,%0);") ;; These patterns match the binary 387 instructions for addM3, subM3, ;; mulM3 and divM3. There are three patterns for each of DFmode and @@ -5633,81 +6920,171 @@ [(match_operand:DF 1 "nonimmediate_operand" "0,fm") (match_operand:DF 2 "nonimmediate_operand" "fm,0")]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (match_operator:DF 3 "binary_387_op" - [(float:DF (match_operand:SI 1 "general_operand" "rm")) - (match_operand:DF 2 "general_operand" "0")]))] + [(float:DF (match_operand:SI 1 "nonimmediate_operand" "rm")) + (match_operand:DF 2 "register_operand" "0")]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (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")]))] + [(match_operand:XF 1 "register_operand" "0,f") + (match_operand:XF 2 "register_operand" "f,0")]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (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")]))] + [(float:XF (match_operand:SI 1 "nonimmediate_operand" "rm")) + (match_operand:XF 2 "register_operand" "0")]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (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")]))] + [(float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,0")) + (match_operand:XF 2 "register_operand" "0,f")]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (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"))]))] + [(match_operand:XF 1 "register_operand" "0") + (float:XF (match_operand:SI 2 "nonimmediate_operand" "rm"))]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (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") + [(match_operand:XF 1 "register_operand" "0,f") (float_extend:XF - (match_operand:SF 2 "general_operand" "fm,0"))]))] + (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f,f") (match_operator:DF 3 "binary_387_op" - [(float_extend:DF (match_operand:SF 1 "general_operand" "fm,0")) - (match_operand:DF 2 "general_operand" "0,f")]))] + [(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,0")) + (match_operand:DF 2 "register_operand" "0,f")]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (match_operator:DF 3 "binary_387_op" - [(match_operand:DF 1 "general_operand" "0") - (float:DF (match_operand:SI 2 "general_operand" "rm"))]))] + [(match_operand:DF 1 "register_operand" "0") + (float:DF (match_operand:SI 2 "nonimmediate_operand" "rm"))]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f,f") (match_operator:DF 3 "binary_387_op" - [(match_operand:DF 1 "general_operand" "0,f") + [(match_operand:DF 1 "register_operand" "0,f") (float_extend:DF - (match_operand:SF 2 "general_operand" "fm,0"))]))] + (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (define_insn "" [(set (match_operand:SF 0 "register_operand" "=f,f") @@ -5715,38 +7092,106 @@ [(match_operand:SF 1 "nonimmediate_operand" "0,fm") (match_operand:SF 2 "nonimmediate_operand" "fm,0")]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (define_insn "" [(set (match_operand:SF 0 "register_operand" "=f") (match_operator:SF 3 "binary_387_op" - [(float:SF (match_operand:SI 1 "general_operand" "rm")) - (match_operand:SF 2 "general_operand" "0")]))] + [(float:SF (match_operand:SI 1 "nonimmediate_operand" "rm")) + (match_operand:SF 2 "register_operand" "0")]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (define_insn "" [(set (match_operand:SF 0 "register_operand" "=f") (match_operator:SF 3 "binary_387_op" - [(match_operand:SF 1 "general_operand" "0") - (float:SF (match_operand:SI 2 "general_operand" "rm"))]))] + [(match_operand:SF 1 "register_operand" "0") + (float:SF (match_operand:SI 2 "nonimmediate_operand" "rm"))]))] "TARGET_80387" - "* return output_387_binary_op (insn, operands);") + "* return output_387_binary_op (insn, operands);" + [(set (attr "type") + (cond [(match_operand:DF 3 "is_mul" "") + (const_string "fpmul") + (match_operand:DF 3 "is_div" "") + (const_string "fpdiv") + ] + (const_string "fpop") + ) + )]) (define_expand "strlensi" [(parallel [(set (match_dup 4) (unspec:SI [(mem:BLK (match_operand:BLK 1 "general_operand" "")) - (match_operand:QI 2 "register_operand" "") + (match_operand:QI 2 "immediate_operand" "") (match_operand:SI 3 "immediate_operand" "")] 0)) (clobber (match_dup 1))]) (set (match_dup 5) (not:SI (match_dup 4))) (set (match_operand:SI 0 "register_operand" "") - (minus:SI (match_dup 5) - (const_int 1)))] + (plus:SI (match_dup 5) + (const_int -1)))] "" " { + if (TARGET_UNROLL_STRLEN && operands[2] == const0_rtx && optimize > 1) + { + rtx address; + rtx scratch; + + /* well it seems that some optimizer does not combine a call like + foo(strlen(bar), strlen(bar)); + when the move and the subtraction is done here. It does calculate + the length just once when these instructions are done inside of + output_strlen_unroll(). But I think since &bar[strlen(bar)] is + often used and I use one fewer register for the lifetime of + output_strlen_unroll() this is better. */ + scratch = gen_reg_rtx (SImode); + address = force_reg (SImode, XEXP (operands[1], 0)); + + /* move address to scratch-register + this is done here because the i586 can do the following and + in the same cycle with the following move. */ + if (GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[3]) < 4) + emit_insn (gen_movsi (scratch, address)); + + emit_insn (gen_movsi (operands[0], address)); + + if(TARGET_USE_Q_REG) + emit_insn (gen_strlensi_unroll5 (operands[0], + operands[3], + scratch, + operands[0])); + else + emit_insn (gen_strlensi_unroll4 (operands[0], + operands[3], + scratch, + operands[0])); + + /* gen_strlensi_unroll[45] returns the address of the zero + at the end of the string, like memchr(), so compute the + length by subtracting the startaddress. */ + emit_insn (gen_subsi3 (operands[0], operands[0], address)); + DONE; + } + operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); operands[4] = gen_reg_rtx (SImode); operands[5] = gen_reg_rtx (SImode); @@ -5759,7 +7204,7 @@ (define_insn "" [(set (match_operand:SI 0 "register_operand" "=&c") (unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "D")) - (match_operand:QI 2 "register_operand" "a") + (match_operand:QI 2 "immediate_operand" "a") (match_operand:SI 3 "immediate_operand" "i")] 0)) (clobber (match_dup 1))] "" @@ -5773,3 +7218,601 @@ output_asm_insn (AS2 (mov%L0,%1,%0), xops); return \"repnz\;scas%B2\"; }") + +/* Conditional move define_insns. */ + +(define_expand "movsicc" + [(set (match_operand:SI 0 "register_operand" "") + (if_then_else:SI (match_operand 1 "comparison_operator" "") + (match_operand:SI 2 "nonimmediate_operand" "") + (match_operand:SI 3 "nonimmediate_operand" "")))] + "TARGET_CMOVE" + " +{ + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); +}") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:SI 4 "nonimmediate_operand" "rm,rm,0,0") + (match_operand:SI 5 "nonimmediate_operand" "0,0,rm,rm")))] + "TARGET_CMOVE" + "#") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:SI 4 "nonimmediate_operand" "rm,rm,0,0") + (match_operand:SI 5 "nonimmediate_operand" "0,0,rm,rm")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT" + "#") + +(define_split + [(set (match_operand:SI 0 "register_operand" "=r,r") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:SI 3 "nonimmediate_operand" "rm,0") + (match_operand:SI 4 "nonimmediate_operand" "0,rm")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 3) (match_dup 4)))] + "") + +(define_split + [(set (match_operand:SI 0 "register_operand" "=r,r") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:SI 4 "nonimmediate_operand" "rm,0") + (match_operand:SI 5 "nonimmediate_operand" "0,rm")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) (compare (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 4) (match_dup 5)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (match_operand:SI 2 "nonimmediate_operand" "rm,0") + (match_operand:SI 3 "nonimmediate_operand" "0,rm")))] + "TARGET_CMOVE && reload_completed" + "* return output_int_conditional_move (which_alternative, operands);") + +(define_expand "movhicc" + [(set (match_operand:HI 0 "register_operand" "") + (if_then_else:HI (match_operand 1 "comparison_operator" "") + (match_operand:HI 2 "nonimmediate_operand" "") + (match_operand:HI 3 "nonimmediate_operand" "")))] + "TARGET_CMOVE" + " +{ + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); +}") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=r,r,r,r") + (if_then_else:HI (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:HI 4 "nonimmediate_operand" "rm,rm,0,0") + (match_operand:HI 5 "nonimmediate_operand" "0,0,rm,rm")))] + "TARGET_CMOVE" + "#") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=r,r,r,r") + (if_then_else:HI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:HI 4 "nonimmediate_operand" "rm,rm,0,0") + (match_operand:HI 5 "nonimmediate_operand" "0,0,rm,rm")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT" + "#") + +(define_split + [(set (match_operand:HI 0 "register_operand" "=r,r") + (if_then_else:HI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:HI 3 "nonimmediate_operand" "rm,0") + (match_operand:HI 4 "nonimmediate_operand" "0,rm")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 0) + (if_then_else:HI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 3) (match_dup 4)))] + "") + +(define_split + [(set (match_operand:HI 0 "register_operand" "=r,r") + (if_then_else:HI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:HI 4 "nonimmediate_operand" "rm,0") + (match_operand:HI 5 "nonimmediate_operand" "0,rm")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (compare (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (if_then_else:HI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 4) (match_dup 5)))] + "") + +(define_insn "" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (if_then_else:HI (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (match_operand:HI 2 "nonimmediate_operand" "rm,0") + (match_operand:HI 3 "nonimmediate_operand" "0,rm")))] + "TARGET_CMOVE && reload_completed" + "* return output_int_conditional_move (which_alternative, operands);") + +(define_expand "movsfcc" + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (match_operand 1 "comparison_operator" "") + (match_operand:SF 2 "register_operand" "") + (match_operand:SF 3 "register_operand" "")))] + "TARGET_CMOVE" + " +{ + rtx temp; + + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + /* The floating point conditional move instructions don't directly + support conditions resulting from a signed integer comparison. */ + + switch (GET_CODE (operands[1])) + { + case LT: + case LE: + case GE: + case GT: + temp = emit_store_flag (gen_reg_rtx (QImode), + GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1, + VOIDmode, 0, 0); + + if (!temp) + FAIL; + + operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx); + break; + + default: + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); + break; + } +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f,f,f") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:SF 4 "register_operand" "f,f,0,0") + (match_operand:SF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f,f,f") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:SF 4 "register_operand" "f,f,0,0") + (match_operand:SF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_split + [(set (match_operand:SF 0 "register_operand" "=f,f") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:SF 3 "register_operand" "f,0") + (match_operand:SF 4 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 0) + (if_then_else:SF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 3) (match_dup 4)))] + "") + +(define_split + [(set (match_operand:SF 0 "register_operand" "=f,f") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:SF 4 "register_operand" "f,0") + (match_operand:SF 5 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) (compare (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (if_then_else:SF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 4) (match_dup 5)))] + "") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (if_then_else:SF (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (match_operand:SF 2 "register_operand" "f,0") + (match_operand:SF 3 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + "* return output_fp_conditional_move (which_alternative, operands);") + +(define_expand "movdfcc" + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (match_operand 1 "comparison_operator" "") + (match_operand:DF 2 "register_operand" "") + (match_operand:DF 3 "register_operand" "")))] + "TARGET_CMOVE" + " +{ + rtx temp; + + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + /* The floating point conditional move instructions don't directly + support conditions resulting from a signed integer comparison. */ + + switch (GET_CODE (operands[1])) + { + case LT: + case LE: + case GE: + case GT: + temp = emit_store_flag (gen_reg_rtx (QImode), + GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1, + VOIDmode, 0, 0); + + if (!temp) + FAIL; + + operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx); + break; + + default: + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); + break; + } +}") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f,f,f") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:DF 4 "register_operand" "f,f,0,0") + (match_operand:DF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f,f,f") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:DF 4 "register_operand" "f,f,0,0") + (match_operand:DF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_split + [(set (match_operand:DF 0 "register_operand" "=f,f") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:DF 3 "register_operand" "f,0") + (match_operand:DF 4 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 0) + (if_then_else:DF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 3) (match_dup 4)))] + "") + +(define_split + [(set (match_operand:DF 0 "register_operand" "=f,f") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:DF 4 "register_operand" "f,0") + (match_operand:DF 5 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) (compare (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (if_then_else:DF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 4) (match_dup 5)))] + "") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (if_then_else:DF (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (match_operand:DF 2 "register_operand" "f,0") + (match_operand:DF 3 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + "* return output_fp_conditional_move (which_alternative, operands);") + +(define_expand "movxfcc" + [(set (match_operand:XF 0 "register_operand" "") + (if_then_else:XF (match_operand 1 "comparison_operator" "") + (match_operand:XF 2 "register_operand" "") + (match_operand:XF 3 "register_operand" "")))] + "TARGET_CMOVE" + " +{ + rtx temp; + + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + /* The floating point conditional move instructions don't directly + support conditions resulting from a signed integer comparison. */ + + switch (GET_CODE (operands[1])) + { + case LT: + case LE: + case GE: + case GT: + temp = emit_store_flag (gen_reg_rtx (QImode), + GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1, + VOIDmode, 0, 0); + + if (!temp) + FAIL; + + operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx); + break; + + default: + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); + break; + } +}") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f,f,f") + (if_then_else:XF (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:XF 4 "register_operand" "f,f,0,0") + (match_operand:XF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f,f,f") + (if_then_else:XF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:XF 4 "register_operand" "f,f,0,0") + (match_operand:XF 5 "register_operand" "0,0,f,f")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE + && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT" + "#") + +(define_split + [(set (match_operand:XF 0 "register_operand" "=f,f") + (if_then_else:XF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:XF 3 "register_operand" "f,0") + (match_operand:XF 4 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 0) + (if_then_else:XF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 3) (match_dup 4)))] + "") + +(define_split + [(set (match_operand:XF 0 "register_operand" "=f,f") + (if_then_else:XF (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:XF 4 "register_operand" "f,0") + (match_operand:XF 5 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) (compare (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (if_then_else:XF (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 4) (match_dup 5)))] + "") + +(define_insn "" + [(set (match_operand:XF 0 "register_operand" "=f,f") + (if_then_else:XF (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (match_operand:XF 2 "register_operand" "f,0") + (match_operand:XF 3 "register_operand" "0,f")))] + "TARGET_CMOVE && reload_completed" + "* return output_fp_conditional_move (which_alternative, operands);") + +(define_expand "movdicc" + [(set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (match_operand 1 "comparison_operator" "") + (match_operand:DI 2 "nonimmediate_operand" "") + (match_operand:DI 3 "nonimmediate_operand" "")))] + "TARGET_CMOVE" + " +{ + if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT) + FAIL; + + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (i386_compare_op0), + i386_compare_op0, i386_compare_op1); +}") + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=&r,&r,&r,&r") + (if_then_else:DI (match_operator 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m") + (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")]) + (match_operand:DI 4 "nonimmediate_operand" "ro,ro,0,0") + (match_operand:DI 5 "nonimmediate_operand" "0,0,ro,ro")))] + "TARGET_CMOVE" + "#") + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=&r,&r,&r,&r") + (if_then_else:DI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "r,m,r,m") + (match_operand 3 "general_operand" "rmi,ri,rmi,ri")]) + (match_operand:DI 4 "nonimmediate_operand" "ro,ro,0,0") + (match_operand:DI 5 "nonimmediate_operand" "0,0,ro,ro")))] + "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT" + "#") + +(define_split + [(set (match_operand:DI 0 "register_operand" "=&r,&r") + (if_then_else:DI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (const_int 0)]) + (match_operand:DI 3 "nonimmediate_operand" "ro,0") + (match_operand:DI 4 "nonimmediate_operand" "0,ro")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) + (match_dup 2)) + (set (match_dup 0) + (if_then_else:DI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 3) (match_dup 4)))] + "") + +(define_split + [(set (match_operand:DI 0 "register_operand" "=&r,&r") + (if_then_else:DI (match_operator 1 "comparison_operator" + [(match_operand 2 "nonimmediate_operand" "") + (match_operand 3 "general_operand" "")]) + (match_operand:DI 4 "nonimmediate_operand" "ro,0") + (match_operand:DI 5 "nonimmediate_operand" "0,ro")))] + "TARGET_CMOVE && reload_completed" + [(set (cc0) (compare (match_dup 2) (match_dup 3))) + (set (match_dup 0) + (if_then_else:DI (match_op_dup 1 [(cc0) (const_int 0)]) + (match_dup 4) (match_dup 5)))] + "") + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=&r,&r") + (if_then_else:DI (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (match_operand:DI 2 "nonimmediate_operand" "ro,0") + (match_operand:DI 3 "nonimmediate_operand" "0,ro")))] + "TARGET_CMOVE && reload_completed" + "* return output_int_conditional_move (which_alternative, operands);") + +(define_insn "strlensi_unroll" + [(set (match_operand:SI 0 "register_operand" "=&r,&r") + (unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "r,r")) + (match_operand:SI 2 "immediate_operand" "i,i")] 0)) + (clobber (match_scratch:SI 3 "=&q,&r"))] + "optimize > 1" + "* return output_strlen_unroll (operands);") + +;; the only difference between the following patterns is the register preference +;; on a pentium using a q-register saves one clock cycle per 4 characters + +(define_insn "strlensi_unroll4" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0,0")) + (match_operand:SI 1 "immediate_operand" "i,i") + (match_operand:SI 2 "register_operand" "+q,!r")] 0)) + (clobber (match_dup 2))] + "(TARGET_USE_ANY_REG && optimize > 1)" + "* return output_strlen_unroll (operands);") + +(define_insn "strlensi_unroll5" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0")) + (match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "register_operand" "+q")] 0)) + (clobber (match_dup 2))] + "(TARGET_USE_Q_REG && optimize > 1)" + "* return output_strlen_unroll (operands);" +) + +(define_insn "allocate_stack_worker" + [(unspec:SI [(match_operand:SI 0 "register_operand" "a")] 3) + (set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 0))) + (clobber (match_dup 0))] + "TARGET_STACK_PROBE" + "* return AS1(call,__alloca);") + +(define_expand "allocate_stack" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (reg:SI 7) (match_operand:SI 1 "general_operand" ""))) + (set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 1)))] + "TARGET_STACK_PROBE" + " +{ +#ifdef CHECK_STACK_LIMIT + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < CHECK_STACK_LIMIT) + emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, + operands[1])); + else +#endif + emit_insn (gen_allocate_stack_worker (copy_to_mode_reg (SImode, + operands[1]))); + + emit_move_insn (operands[0], virtual_stack_dynamic_rtx); + DONE; +}") + +(define_expand "exception_receiver" + [(const_int 0)] + "flag_pic" + " +{ + load_pic_register (1); + DONE; +}") |