--- gcc/config/i386.md 2018/04/24 17:51:37 1.1.1.1 +++ gcc/config/i386.md 2018/04/24 18:06:05 1.1.1.4 @@ -19,37 +19,44 @@ ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -;;- instruction definitions +;; The original PO technology requires these to be ordered by speed, +;; so that assigner will pick the fastest. -;;- @@The original PO technology requires these to be ordered by speed, -;;- @@ so that assigner will pick the fastest. +;; See file "rtl.def" for documentation on define_insn, match_*, et. al. -;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;; Macro #define NOTICE_UPDATE_CC in file i386.h handles condition code +;; updates for most instructions. -;;- When naming insn's (operand 0 of define_insn) be careful about using -;;- names from other targets machine descriptions. - -;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code -;;- updates for most instructions. - -;;- Operand classes for the register allocator: -;;- 'a' for eax -;;- 'd' for edx -;;- 'c' for ecx -;;- 'b' for ebx -;;- 'f' for anything in FLOAT_REGS -;;- 'r' any (non-floating-point) register -;;- 'q' regs that allow byte operations (A, B, C and D) -;;- 'A' A and D registers +;; Macro REG_CLASS_FROM_LETTER in file i386.h defines the register +;; constraint letters. ;; the special asm out single letter directives following a '%' are: -;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of operands[1] -;; 's' output a '*' -;; 'w' If the operand is a REG, it uses the mode size to determine the -;; printing of the reg - +;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of +;; operands[1]. +;; '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. + +;; 'b' Print the QImode name of the register for the indicated operand. +;; %b0 would print %al if operands[0] is reg 0. +;; 'w' Likewise, print the HImode name of the register. +;; 'k' Likewise, print the SImode name of the register. +;; 'h' Print the QImode name for a "high" register, either ah, bh, ch or dh. +;; 'y' Print "st(0)" instead of "st" as a register. + +;; UNSPEC usage: +;; 0 This is a `scas' operation. The mode of the UNSPEC is always SImode. +;; operand 0 is the memory address to scan. +;; operand 1 is a register containing the value to scan for. The mode +;; of the scas opcode will be the same as the mode of this operand. +;; operand 2 is the known alignment of operand 0. +;; 1 This is a `sin' operation. The mode of the UNSPEC is MODE_FLOAT. +;; 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'. - ;; "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 ;; test in cases like "incl MEM / je TARGET". @@ -58,7 +65,11 @@ ;; (set (cc0) (const_int foo)) has no mode information. Such insns will ;; be folded while optimizing anyway. -(define_insn "tstsi" +;; All test insns have expanders that save the operands away without +;; actually generating RTL. The bCOND or sCOND (emitted immediately +;; after the tstM or cmp) will actually emit the tstM or cmpM. + +(define_insn "tstsi_cc" [(set (cc0) (match_operand:SI 0 "nonimmediate_operand" "rm"))] "" @@ -71,7 +82,18 @@ return AS2 (cmp%L0,%1,%0); }") -(define_insn "tsthi" +(define_expand "tstsi" + [(set (cc0) + (match_operand:SI 0 "nonimmediate_operand" ""))] + "" + " +{ + i386_compare_gen = gen_tstsi_cc; + i386_compare_op0 = operands[0]; + DONE; +}") + +(define_insn "tsthi_cc" [(set (cc0) (match_operand:HI 0 "nonimmediate_operand" "rm"))] "" @@ -84,7 +106,18 @@ return AS2 (cmp%W0,%1,%0); }") -(define_insn "tstqi" +(define_expand "tsthi" + [(set (cc0) + (match_operand:HI 0 "nonimmediate_operand" ""))] + "" + " +{ + i386_compare_gen = gen_tsthi_cc; + i386_compare_op0 = operands[0]; + DONE; +}") + +(define_insn "tstqi_cc" [(set (cc0) (match_operand:QI 0 "nonimmediate_operand" "qm"))] "" @@ -97,54 +130,90 @@ return AS2 (cmp%B0,%1,%0); }") -(define_insn "tstsf" +(define_expand "tstqi" + [(set (cc0) + (match_operand:QI 0 "nonimmediate_operand" ""))] + "" + " +{ + i386_compare_gen = gen_tstqi_cc; + i386_compare_op0 = operands[0]; + DONE; +}") + +(define_insn "tstsf_cc" [(set (cc0) (match_operand:SF 0 "register_operand" "f")) (clobber (match_scratch:HI 1 "=a"))] - "TARGET_80387" + "TARGET_80387 && ! TARGET_IEEE_FP" "* { if (! STACK_TOP_P (operands[0])) abort (); output_asm_insn (\"ftst\", operands); - cc_status.flags |= CC_IN_80387; if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) output_asm_insn (AS1 (fstp,%y0), operands); - output_asm_insn (AS1 (fnsts%W1,%1), operands); + return (char *) output_fp_cc0_set (insn); +}") + +;; Don't generate tstsf if generating IEEE code, since the `ftst' opcode +;; isn't IEEE compliant. - return \"sahf\"; +(define_expand "tstsf" + [(parallel [(set (cc0) + (match_operand:SF 0 "register_operand" "")) + (clobber (match_scratch:HI 1 ""))])] + "TARGET_80387 && ! TARGET_IEEE_FP" + " +{ + i386_compare_gen = gen_tstsf_cc; + i386_compare_op0 = operands[0]; + DONE; }") -(define_insn "tstdf" +(define_insn "tstdf_cc" [(set (cc0) (match_operand:DF 0 "register_operand" "f")) (clobber (match_scratch:HI 1 "=a"))] - "TARGET_80387" + "TARGET_80387 && ! TARGET_IEEE_FP" "* { if (! STACK_TOP_P (operands[0])) abort (); output_asm_insn (\"ftst\", operands); - cc_status.flags |= CC_IN_80387; if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG)) output_asm_insn (AS1 (fstp,%y0), operands); - output_asm_insn (AS1 (fnsts%W1,%1), operands); + return (char *) output_fp_cc0_set (insn); +}") + +;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode +;; isn't IEEE compliant. - return \"sahf\"; +(define_expand "tstdf" + [(parallel [(set (cc0) + (match_operand:DF 0 "register_operand" "")) + (clobber (match_scratch:HI 1 ""))])] + "TARGET_80387 && ! TARGET_IEEE_FP" + " +{ + i386_compare_gen = gen_tstdf_cc; + i386_compare_op0 = operands[0]; + DONE; }") -;;- compare instructions +;;- compare instructions. See comments above tstM patterns about +;; expansion of these insns. -(define_insn "cmpsi" +(define_insn "cmpsi_cc" [(set (cc0) - (compare (match_operand:SI 0 "nonimmediate_operand" "mr,ri") - (match_operand:SI 1 "general_operand" "ri,mr")))] + (compare:CC (match_operand:SI 0 "nonimmediate_operand" "mr,ri") + (match_operand:SI 1 "general_operand" "ri,mr")))] "" "* { @@ -156,10 +225,23 @@ return AS2 (cmp%L0,%1,%0); }") -(define_insn "cmphi" +(define_expand "cmpsi" [(set (cc0) - (compare (match_operand:HI 0 "nonimmediate_operand" "mr,ri") - (match_operand:HI 1 "general_operand" "ri,mr")))] + (compare:CC (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "general_operand" "")))] + "" + " +{ + i386_compare_gen = gen_cmpsi_cc; + i386_compare_op0 = operands[0]; + i386_compare_op1 = operands[1]; + DONE; +}") + +(define_insn "cmphi_cc" + [(set (cc0) + (compare:CC (match_operand:HI 0 "nonimmediate_operand" "mr,ri") + (match_operand:HI 1 "general_operand" "ri,mr")))] "" "* { @@ -171,10 +253,23 @@ return AS2 (cmp%W0,%1,%0); }") -(define_insn "cmpqi" +(define_expand "cmphi" + [(set (cc0) + (compare:CC (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" "")))] + "" + " +{ + i386_compare_gen = gen_cmphi_cc; + i386_compare_op0 = operands[0]; + i386_compare_op1 = operands[1]; + DONE; +}") + +(define_insn "cmpqi_cc" [(set (cc0) - (compare (match_operand:QI 0 "nonimmediate_operand" "qn,mq") - (match_operand:QI 1 "general_operand" "qm,nq")))] + (compare:CC (match_operand:QI 0 "nonimmediate_operand" "qn,mq") + (match_operand:QI 1 "general_operand" "qm,nq")))] "" "* { @@ -186,96 +281,194 @@ return AS2 (cmp%B0,%1,%0); }") +(define_expand "cmpqi" + [(set (cc0) + (compare:CC (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" "")))] + "" + " +{ + i386_compare_gen = gen_cmpqi_cc; + i386_compare_op0 = operands[0]; + i386_compare_op1 = operands[1]; + DONE; +}") + ;; These implement float point compares. For each of DFmode and ;; SFmode, there is the normal insn, and an insn where the second operand ;; is converted to the desired mode. -(define_expand "cmpdf" - [(parallel [(set (cc0) - (compare (match_operand:DF 0 "nonimmediate_operand" "") - (match_operand:DF 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:HI 2 ""))])] +(define_insn "cmpdf_cc" + [(set (cc0) + (compare:CC (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "nonimmediate_operand" "fm"))) + (clobber (match_scratch:HI 2 "=a"))] "TARGET_80387" - "") + "* return (char *) output_float_compare (insn, operands);") -(define_expand "cmpsf" - [(parallel [(set (cc0) - (compare (match_operand:SF 0 "nonimmediate_operand" "") - (match_operand:SF 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:HI 2 ""))])] +(define_insn "" + [(set (cc0) + (compare:CC (match_operand:DF 0 "register_operand" "f,f") + (float:DF + (match_operand:SI 1 "nonimmediate_operand" "m,!*r")))) + (clobber (match_scratch:HI 2 "=a,a"))] "TARGET_80387" - "") + "* return (char *) output_float_compare (insn, operands);") -;; The `ble' and `blt' patterns can reverse a compare, so we must allow -;; an immediate operand as operand 0 in the recognizers below. +(define_insn "" + [(set (cc0) + (compare:CC (match_operand:DF 0 "register_operand" "f,f") + (float_extend:DF + (match_operand:SF 1 "nonimmediate_operand" "fm,!*r")))) + (clobber (match_scratch:HI 2 "=a,a"))] + "TARGET_80387" + "* return (char *) output_float_compare (insn, operands);") (define_insn "" [(set (cc0) - (compare (match_operand:DF 0 "general_operand" "f") - (match_operand:DF 1 "general_operand" "fm"))) + (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f") + (match_operand:DF 1 "register_operand" "f"))) (clobber (match_scratch:HI 2 "=a"))] "TARGET_80387" "* return (char *) output_float_compare (insn, operands);") (define_insn "" [(set (cc0) - (compare (match_operand:DF 0 "general_operand" "f,f") - (float:DF (match_operand:SI 1 "general_operand" "m,!*r")))) - (clobber (match_scratch:HI 2 "=a,a"))] + (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f") + (float_extend:DF + (match_operand:SF 1 "register_operand" "f")))) + (clobber (match_scratch:HI 2 "=a"))] + "TARGET_80387" + "* return (char *) output_float_compare (insn, operands);") + +(define_insn "cmpsf_cc" + [(set (cc0) + (compare:CC (match_operand:SF 0 "register_operand" "f") + (match_operand:SF 1 "nonimmediate_operand" "fm"))) + (clobber (match_scratch:HI 2 "=a"))] "TARGET_80387" "* return (char *) output_float_compare (insn, operands);") (define_insn "" [(set (cc0) - (compare (match_operand:DF 0 "general_operand" "f,f") - (float_extend:DF - (match_operand:SF 1 "general_operand" "fm,!*r")))) + (compare:CC (match_operand:SF 0 "register_operand" "f,f") + (float:SF + (match_operand:SI 1 "nonimmediate_operand" "m,!*r")))) (clobber (match_scratch:HI 2 "=a,a"))] "TARGET_80387" "* return (char *) output_float_compare (insn, operands);") (define_insn "" [(set (cc0) - (compare (match_operand:SF 0 "general_operand" "f") - (match_operand:SF 1 "general_operand" "fm"))) + (compare:CCFPEQ (match_operand:SF 0 "register_operand" "f") + (match_operand:SF 1 "register_operand" "f"))) (clobber (match_scratch:HI 2 "=a"))] "TARGET_80387" "* return (char *) output_float_compare (insn, operands);") -(define_insn "" +(define_expand "cmpdf" [(set (cc0) - (compare (match_operand:SF 0 "general_operand" "f,f") - (float:SF (match_operand:SI 1 "general_operand" "m,!*r")))) - (clobber (match_scratch:HI 2 "=a,a"))] + (compare:CC (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "nonimmediate_operand" "")))] "TARGET_80387" - "* return (char *) output_float_compare (insn, operands);") + " +{ + i386_compare_gen = gen_cmpdf_cc; + i386_compare_gen_eq = gen_cmpdf_ccfpeq; + i386_compare_op0 = operands[0]; + i386_compare_op1 = operands[1]; + DONE; +}") + +(define_expand "cmpsf" + [(set (cc0) + (compare:CC (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "nonimmediate_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]; + DONE; +}") + +(define_expand "cmpdf_ccfpeq" + [(parallel [(set (cc0) + (compare:CCFPEQ (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "register_operand" ""))) + (clobber (match_scratch:HI 2 ""))])] + "TARGET_80387" + " +{ + if (! register_operand (operands[1], DFmode)) + operands[1] = copy_to_mode_reg (DFmode, operands[1]); +}") + +(define_expand "cmpsf_ccfpeq" + [(parallel [(set (cc0) + (compare:CCFPEQ (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "register_operand" ""))) + (clobber (match_scratch:HI 2 ""))])] + "TARGET_80387" + " +{ + if (! register_operand (operands[1], SFmode)) + operands[1] = copy_to_mode_reg (SFmode, operands[1]); +}") ;; logical compare -;; ??? What if we are testing one byte of an offsettable memory reference? (define_insn "" [(set (cc0) - (and:SI (match_operand:SI 0 "general_operand" "%rm") + (and:SI (match_operand:SI 0 "general_operand" "%ro") (match_operand:SI 1 "general_operand" "ri")))] "" "* { /* For small integers, we may actually use testb. */ if (GET_CODE (operands[1]) == CONST_INT - && (INTVAL (operands[1]) & ~0xffff) == 0 - && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) + && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + && (! REG_P (operands[0]) || QI_REG_P (operands[0]))) { /* We may set the sign bit spuriously. */ - cc_status.flags |= CC_NOT_NEGATIVE; - if (! NON_QI_REG_P (operands[0]) && (INTVAL (operands[1]) & ~0xff) == 0) - return AS2 (test%B0,%1,%b0); + if ((INTVAL (operands[1]) & ~0xff) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + return AS2 (test%B0,%1,%b0); + } - if (QI_REG_P (operands[0]) && (INTVAL (operands[1]) & ~0xff00) == 0) + if ((INTVAL (operands[1]) & ~0xff00) == 0) { - operands[1] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[1]) >> 8); - return AS2 (test%B0,%1,%h0); + cc_status.flags |= CC_NOT_NEGATIVE; + operands[1] = GEN_INT (INTVAL (operands[1]) >> 8); + + if (QI_REG_P (operands[0])) + return AS2 (test%B0,%1,%h0); + else + { + operands[0] = adj_offsettable_operand (operands[0], 1); + return AS2 (test%B0,%1,%b0); + } + } + + if (GET_CODE (operands[0]) == MEM + && (INTVAL (operands[1]) & ~0xff0000) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + operands[1] = GEN_INT (INTVAL (operands[1]) >> 16); + operands[0] = adj_offsettable_operand (operands[0], 2); + return AS2 (test%B0,%1,%b0); + } + + if (GET_CODE (operands[0]) == MEM + && (INTVAL (operands[1]) & ~0xff000000) == 0) + { + operands[1] = GEN_INT ((INTVAL (operands[1]) >> 24) & 0xff); + operands[0] = adj_offsettable_operand (operands[0], 3); + return AS2 (test%B0,%1,%b0); } } @@ -287,34 +480,37 @@ (define_insn "" [(set (cc0) - (and:HI (match_operand:HI 0 "general_operand" "%rm") + (and:HI (match_operand:HI 0 "general_operand" "%ro") (match_operand:HI 1 "general_operand" "ri")))] "" "* { if (GET_CODE (operands[1]) == CONST_INT - && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) + && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])) + && (! REG_P (operands[0]) || QI_REG_P (operands[0]))) { - /* Can we ignore the upper byte? */ - if (! NON_QI_REG_P (operands[0]) - && (INTVAL (operands[1]) & 0xff00) == 0) + if ((INTVAL (operands[1]) & 0xff00) == 0) { + /* ??? This might not be necessary. */ if (INTVAL (operands[1]) & 0xffff0000) - operands[1] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[1]) & 0xff); + operands[1] = GEN_INT (INTVAL (operands[1]) & 0xff); /* We may set the sign bit spuriously. */ cc_status.flags |= CC_NOT_NEGATIVE; return AS2 (test%B0,%1,%b0); } - /* Can we ignore the lower byte? */ - /* ??? what about offsettable memory references? */ - if (QI_REG_P (operands[0]) && (INTVAL (operands[1]) & 0xff) == 0) + if ((INTVAL (operands[1]) & 0xff) == 0) { - operands[1] = gen_rtx (CONST_INT, VOIDmode, - (INTVAL (operands[1]) >> 8) & 0xff); - return AS2 (test%B0,%1,%h0); + operands[1] = GEN_INT ((INTVAL (operands[1]) >> 8) & 0xff); + + if (QI_REG_P (operands[0])) + return AS2 (test%B0,%1,%h0); + else + { + operands[0] = adj_offsettable_operand (operands[0], 1); + return AS2 (test%B0,%1,%b0); + } } } @@ -560,7 +756,7 @@ abort (); xops[0] = AT_SP (SFmode); - xops[1] = gen_rtx (CONST_INT, VOIDmode, 4); + xops[1] = GEN_INT (4); xops[2] = stack_pointer_rtx; output_asm_insn (AS2 (sub%L2,%1,%2), xops); @@ -641,7 +837,7 @@ rtx xops[3]; xops[0] = AT_SP (SFmode); - xops[1] = gen_rtx (CONST_INT, VOIDmode, 8); + xops[1] = GEN_INT (8); xops[2] = stack_pointer_rtx; output_asm_insn (AS2 (sub%L2,%1,%2), xops); @@ -736,7 +932,7 @@ }") (define_insn "movdi" - [(set (match_operand:DI 0 "general_operand" "=&r,rm") + [(set (match_operand:DI 0 "general_operand" "=r,rm") (match_operand:DI 1 "general_operand" "m,riF"))] "" "* @@ -747,47 +943,6 @@ ;;- conversion instructions ;;- NONE -;;- truncation instructions - -(define_insn "truncsiqi2" - [(set (match_operand:QI 0 "general_operand" "=q,qm") - (truncate:QI - (match_operand:SI 1 "general_operand" "qim,qn")))] - "" - "* -{ - if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT) - return AS2 (mov%L0,%1,%k0); - - return AS2 (mov%B0,%b1,%0); -}") - -(define_insn "trunchiqi2" - [(set (match_operand:QI 0 "general_operand" "=q,qm") - (truncate:QI - (match_operand:HI 1 "general_operand" "qim,qn")))] - "" - "* -{ - if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT) - return AS2 (mov%L0,%1,%k0); - - return AS2 (mov%B0,%b1,%0); -}") - -(define_insn "truncsihi2" - [(set (match_operand:HI 0 "general_operand" "=r,rm") - (truncate:HI - (match_operand:SI 1 "general_operand" "rim,rn")))] - "" - "* -{ - if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != CONST_INT) - return AS2 (mov%L0,%1,%k0); - - return AS2 (mov%W0,%w1,%0); -}") - ;;- zero extension instructions ;; See comments by `andsi' for when andl is faster than movzx. @@ -803,7 +958,7 @@ { rtx xops[2]; xops[0] = operands[0]; - xops[1] = gen_rtx (CONST_INT, VOIDmode, 0xffff); + xops[1] = GEN_INT (0xffff); output_asm_insn (AS2 (and%L0,%1,%k0), xops); RET; } @@ -827,7 +982,7 @@ { rtx xops[2]; xops[0] = operands[0]; - xops[1] = gen_rtx (CONST_INT, VOIDmode, 0xff); + xops[1] = GEN_INT (0xff); output_asm_insn (AS2 (and%L0,%1,%k0), xops); RET; } @@ -851,7 +1006,7 @@ { rtx xops[2]; xops[0] = operands[0]; - xops[1] = gen_rtx (CONST_INT, VOIDmode, 0xff); + xops[1] = GEN_INT (0xff); output_asm_insn (AS2 (and%L0,%1,%k0), xops); RET; } @@ -1005,11 +1160,12 @@ ;; part. (define_expand "fixuns_truncdfsi2" - [(parallel [(set (match_dup 3) - (fix:DI - (fix:DF (match_operand:DF 1 "register_operand" "")))) + [(set (match_dup 5) + (match_operand:DF 1 "register_operand" "")) + (parallel [(set (match_dup 3) + (fix:DI (fix:DF (match_dup 5)))) (clobber (match_scratch:HI 2 "")) - (clobber (match_dup 1))]) + (clobber (match_dup 5))]) (set (match_operand:SI 0 "general_operand" "") (match_dup 4))] "TARGET_80387" @@ -1017,14 +1173,16 @@ { operands[3] = gen_reg_rtx (DImode); operands[4] = gen_lowpart (SImode, operands[3]); + operands[5] = gen_reg_rtx (DFmode); }") (define_expand "fixuns_truncsfsi2" - [(parallel [(set (match_dup 3) - (fix:DI - (fix:SF (match_operand:SF 1 "register_operand" "")))) + [(set (match_dup 5) + (match_operand:SF 1 "register_operand" "")) + (parallel [(set (match_dup 3) + (fix:DI (fix:SF (match_dup 5)))) (clobber (match_scratch:HI 2 "")) - (clobber (match_dup 1))]) + (clobber (match_dup 5))]) (set (match_operand:SI 0 "general_operand" "") (match_dup 4))] "TARGET_80387" @@ -1032,35 +1190,40 @@ { operands[3] = gen_reg_rtx (DImode); operands[4] = gen_lowpart (SImode, operands[3]); + operands[5] = gen_reg_rtx (SFmode); }") ;; Signed conversion to DImode. (define_expand "fix_truncdfdi2" - [(parallel [(set (match_operand:DI 0 "general_operand" "") - (fix:DI - (fix:DF (match_operand:DF 1 "register_operand" "")))) + [(set (match_dup 3) + (match_operand:DF 1 "register_operand" "")) + (parallel [(set (match_operand:DI 0 "general_operand" "") + (fix:DI (fix:DF (match_dup 3)))) (clobber (match_scratch:HI 2 "")) - (clobber (match_dup 1))])] + (clobber (match_dup 3))])] "TARGET_80387" " { operands[1] = copy_to_mode_reg (DFmode, operands[1]); + operands[3] = gen_reg_rtx (DFmode); }") (define_expand "fix_truncsfdi2" - [(parallel [(set (match_operand:DI 0 "general_operand" "") - (fix:DI - (fix:SF (match_operand:SF 1 "register_operand" "")))) + [(set (match_dup 3) + (match_operand:SF 1 "register_operand" "")) + (parallel [(set (match_operand:DI 0 "general_operand" "") + (fix:DI (fix:SF (match_dup 3)))) (clobber (match_scratch:HI 2 "")) - (clobber (match_dup 1))])] + (clobber (match_dup 3))])] "TARGET_80387" " { operands[1] = copy_to_mode_reg (SFmode, operands[1]); + operands[3] = gen_reg_rtx (SFmode); }") -;; These match a signed convertion of either DFmode or SFmode to DImode. +;; These match a signed conversion of either DFmode or SFmode to DImode. (define_insn "" [(set (match_operand:DI 0 "general_operand" "=m,!*r") @@ -1113,7 +1276,7 @@ ;; Conversion between fixed point and floating point. ;; The actual pattern that matches these is at the end of this file. -;; ??? Possibly repsent floatunssidf2 here in gcc2. +;; ??? Possibly represent floatunssidf2 here in gcc2. (define_expand "floatsisf2" [(set (match_operand:SF 0 "register_operand" "") @@ -1142,11 +1305,43 @@ ;; This will convert from SImode or DImode to MODE_FLOAT. (define_insn "" - [(set (match_operand 0 "register_operand" "=f,f") - (match_operator 2 "float_op" - [(match_operand:DI 1 "general_operand" "m,!*r")]))] - "TARGET_80387 && GET_MODE (operands[0]) == GET_MODE (operands[2]) - && GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_FLOAT" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (float:DF (match_operand:DI 1 "general_operand" "m,!*r")))] + "TARGET_80387" + "* +{ + if (NON_STACK_REG_P (operands[1])) + { + output_op_from_reg (operands[1], AS1 (fild%z0,%1)); + RET; + } + else if (GET_CODE (operands[1]) == MEM) + return AS1 (fild%z1,%1); + else + abort (); +}") + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (float:SF (match_operand:DI 1 "general_operand" "m,!*r")))] + "TARGET_80387" + "* +{ + if (NON_STACK_REG_P (operands[1])) + { + output_op_from_reg (operands[1], AS1 (fild%z0,%1)); + RET; + } + else if (GET_CODE (operands[1]) == MEM) + return AS1 (fild%z1,%1); + else + abort (); +}") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (float:DF (match_operand:SI 1 "general_operand" "m,!*r")))] + "TARGET_80387" "* { if (NON_STACK_REG_P (operands[1])) @@ -1161,11 +1356,9 @@ }") (define_insn "" - [(set (match_operand 0 "register_operand" "=f,f") - (match_operator 2 "float_op" - [(match_operand:SI 1 "general_operand" "m,!*r")]))] - "TARGET_80387 && GET_MODE (operands[0]) == GET_MODE (operands[2]) - && GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_FLOAT" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (float:SF (match_operand:SI 1 "general_operand" "m,!*r")))] + "TARGET_80387" "* { if (NON_STACK_REG_P (operands[1])) @@ -1217,8 +1410,20 @@ if (! TARGET_486 || ! REG_P (operands[2])) { CC_STATUS_INIT; - operands[1] = SET_SRC (PATTERN (insn)); - return AS2 (lea%L0,%a1,%0); + + if (operands[2] == stack_pointer_rtx) + { + rtx temp; + + temp = operands[1]; + operands[1] = operands[2]; + operands[2] = temp; + } + if (operands[2] != stack_pointer_rtx) + { + operands[1] = SET_SRC (PATTERN (insn)); + return AS2 (lea%L0,%a1,%0); + } } output_asm_insn (AS2 (mov%L0,%1,%0), operands); @@ -1448,7 +1653,7 @@ return AS3 (imul%L0,%2,%1,%0); }") -(define_insn "mulqihi3_1" +(define_insn "" [(set (match_operand:HI 0 "general_operand" "=a") (mult:SI (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0")) @@ -1643,8 +1848,7 @@ return AS2 (mov%B0,%2,%b0); } - operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2]) & 0xff); + operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff); return AS2 (and%B0,%2,%b0); } @@ -1658,8 +1862,7 @@ return AS2 (mov%B0,%2,%h0); } - operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2]) >> 8); + operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff); return AS2 (and%B0,%2,%h0); } @@ -1684,7 +1887,7 @@ && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) { /* Can we ignore the upper byte? */ - if (! NON_QI_REG_P (operands[0]) + if ((! REG_P (operands[0]) || QI_REG_P (operands[0])) && (INTVAL (operands[2]) & 0xff00) == 0xff00) { CC_STATUS_INIT; @@ -1695,8 +1898,7 @@ return AS2 (mov%B0,%2,%b0); } - operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2]) & 0xff); + operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff); return AS2 (and%B0,%2,%b0); } @@ -1712,8 +1914,7 @@ return AS2 (mov%B0,%2,%h0); } - operands[2] = gen_rtx (CONST_INT, VOIDmode, - (INTVAL (operands[2]) >> 8) & 0xff); + operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff); return AS2 (and%B0,%2,%h0); } } @@ -1765,7 +1966,8 @@ if (GET_CODE (operands[2]) == CONST_INT && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) { - if (! NON_QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff) == 0) + if ((! REG_P (operands[0]) || QI_REG_P (operands[0])) + && (INTVAL (operands[2]) & ~0xff) == 0) { CC_STATUS_INIT; @@ -1778,8 +1980,7 @@ if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff00) == 0) { CC_STATUS_INIT; - operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2]) >> 8); + operands[2] = GEN_INT (INTVAL (operands[2]) >> 8); if (INTVAL (operands[2]) == 0xff) return AS2 (mov%B0,%2,%h0); @@ -1802,13 +2003,12 @@ && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) { /* Can we ignore the upper byte? */ - if (! NON_QI_REG_P (operands[0]) + 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_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2]) & 0xffff); + operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff); if (INTVAL (operands[2]) == 0xff) return AS2 (mov%B0,%2,%b0); @@ -1822,8 +2022,7 @@ && (INTVAL (operands[2]) & 0xff) == 0) { CC_STATUS_INIT; - operands[2] = gen_rtx (CONST_INT, VOIDmode, - (INTVAL (operands[2]) >> 8) & 0xff); + operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff); if (INTVAL (operands[2]) == 0xff) return AS2 (mov%B0,%2,%h0); @@ -1855,12 +2054,13 @@ if (GET_CODE (operands[2]) == CONST_INT && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) { - if (! NON_QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff) == 0) + if ((! REG_P (operands[0]) || QI_REG_P (operands[0])) + && (INTVAL (operands[2]) & ~0xff) == 0) { CC_STATUS_INIT; if (INTVAL (operands[2]) == 0xff) - return AS1 (not%B0,%0); + return AS1 (not%B0,%b0); return AS2 (xor%B0,%2,%b0); } @@ -1868,8 +2068,7 @@ if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff00) == 0) { CC_STATUS_INIT; - operands[2] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2]) >> 8); + operands[2] = GEN_INT (INTVAL (operands[2]) >> 8); if (INTVAL (operands[2]) == 0xff) return AS1 (not%B0,%h0); @@ -1892,16 +2091,15 @@ && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))) { /* Can we ignore the upper byte? */ - if (! NON_QI_REG_P (operands[0]) + 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_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2]) & 0xffff); + operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff); if (INTVAL (operands[2]) == 0xff) - return AS1 (not%B0,%0); + return AS1 (not%B0,%b0); return AS2 (xor%B0,%2,%b0); } @@ -1912,8 +2110,7 @@ && (INTVAL (operands[2]) & 0xff) == 0) { CC_STATUS_INIT; - operands[2] = gen_rtx (CONST_INT, VOIDmode, - (INTVAL (operands[2]) >> 8) & 0xff); + operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff); if (INTVAL (operands[2]) == 0xff) return AS1 (not%B0,%h0); @@ -2013,21 +2210,59 @@ (define_insn "sqrtsf2" [(set (match_operand:SF 0 "register_operand" "=f") (sqrt:SF (match_operand:SF 1 "general_operand" "0")))] - "TARGET_80387" + "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" "fsqrt") (define_insn "sqrtdf2" [(set (match_operand:DF 0 "register_operand" "=f") (sqrt:DF (match_operand:DF 1 "general_operand" "0")))] - "TARGET_80387" + "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" "fsqrt") (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (sqrt:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))] - "TARGET_80387" + "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" "fsqrt") + +(define_insn "sindf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))] + "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "fsin") + +(define_insn "sinsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))] + "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "fsin") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(float_extend:DF + (match_operand:SF 1 "register_operand" "0"))] 1))] + "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "fsin") + +(define_insn "cosdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))] + "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "fcos") + +(define_insn "cossf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))] + "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "fcos") + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(float_extend:DF + (match_operand:SF 1 "register_operand" "0"))] 2))] + "TARGET_80387 && (TARGET_IEEE_FP || flag_fast_math)" + "fcos") ;;- one complement instructions @@ -2074,11 +2309,30 @@ ;; shift pair, instead using moves and sign extension for counts greater ;; than 31. -(define_insn "ashldi3" - [(set (match_operand:DI 0 "general_operand" "=&r") - (ashift:DI (match_operand:DI 1 "general_operand" "0") - (match_operand:QI 2 "general_operand" "cJ"))) - (clobber (match_dup 2))] +(define_expand "ashldi3" + [(set (match_operand:DI 0 "register_operand" "") + (ashift:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')) + { + operands[2] = copy_to_mode_reg (QImode, operands[2]); + emit_insn (gen_ashldi3_non_const_int (operands[0], operands[1], + operands[2])); + } + else + emit_insn (gen_ashldi3_const_int (operands[0], operands[1], operands[2])); + + DONE; +}") + +(define_insn "ashldi3_const_int" + [(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")))] "" "* { @@ -2092,42 +2346,57 @@ xops[2] = low[0]; xops[3] = high[0]; - if (REG_P (xops[0])) /* If shift count in %cl */ + if (INTVAL (xops[0]) > 31) { - output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */ + output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */ + output_asm_insn (AS2 (xor%L2,%2,%2), xops); - output_asm_insn (AS2 (shld%L3,%2,%3), xops); - output_asm_insn (AS2 (sal%L2,%0,%2), xops); - output_asm_insn (AS2 (shld%L3,%2,%3), xops); + if (INTVAL (xops[0]) > 32) + { + xops[0] = GEN_INT (INTVAL (xops[0]) - 32); + output_asm_insn (AS2 (sal%L3,%0,%3), xops); /* Remaining shift */ + } + } + else + { + output_asm_insn (AS3 (shld%L3,%0,%2,%3), xops); output_asm_insn (AS2 (sal%L2,%0,%2), xops); + } + RET; +}") - xops[1] = gen_rtx (CONST_INT, VOIDmode, 7); /* shift count & 1 */ +(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))] + "" + "* +{ + rtx xops[4], low[1], high[1]; - output_asm_insn (AS2 (shr%B0,%1,%0), xops); + CC_STATUS_INIT; - output_asm_insn (AS2 (shld%L3,%2,%3), xops); - output_asm_insn (AS2 (sal%L2,%0,%2), xops); - } - else if (GET_CODE (xops[0]) == CONST_INT) - { - if (INTVAL (xops[0]) > 31) - { - output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */ - output_asm_insn (AS2 (xor%L2,%2,%2), xops); + split_di (operands, 1, low, high); + xops[0] = operands[2]; + xops[1] = const1_rtx; + xops[2] = low[0]; + xops[3] = high[0]; - if (INTVAL (xops[0]) > 32) - { - xops[0] = gen_rtx (CONST_INT, VOIDmode, INTVAL (xops[0]) - 32); + output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */ + + 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 (sal%3,%0,%3), xops); /* Remaining shift */ - } - } - else - { - output_asm_insn (AS3 (shld%L3,%0,%2,%3), xops); - output_asm_insn (AS2 (sal%L2,%0,%2), xops); - } - } RET; }") @@ -2138,7 +2407,7 @@ (define_insn "ashlsi3" [(set (match_operand:SI 0 "general_operand" "=r,rm") (ashift:SI (match_operand:SI 1 "general_operand" "r,0") - (match_operand:SI 2 "general_operand" "M,cI")))] + (match_operand:SI 2 "nonmemory_operand" "M,cI")))] "" "* { @@ -2152,9 +2421,14 @@ else { CC_STATUS_INIT; + + if (operands[1] == stack_pointer_rtx) + { + output_asm_insn (AS2 (mov%L0,%1,%0), operands); + operands[1] = operands[0]; + } operands[1] = gen_rtx (MULT, SImode, operands[1], - gen_rtx (CONST_INT, VOIDmode, - 1 << INTVAL (operands[2]))); + GEN_INT (1 << INTVAL (operands[2]))); return AS2 (lea%L0,%a1,%0); } } @@ -2171,7 +2445,7 @@ (define_insn "ashlhi3" [(set (match_operand:HI 0 "general_operand" "=rm") (ashift:HI (match_operand:HI 1 "general_operand" "0") - (match_operand:HI 2 "general_operand" "cI")))] + (match_operand:HI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2187,7 +2461,7 @@ (define_insn "ashlqi3" [(set (match_operand:QI 0 "general_operand" "=qm") (ashift:QI (match_operand:QI 1 "general_operand" "0") - (match_operand:QI 2 "general_operand" "cI")))] + (match_operand:QI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2202,15 +2476,34 @@ ;; See comment above `ashldi3' about how this works. -(define_insn "ashrdi3" - [(set (match_operand:DI 0 "general_operand" "=&r") - (ashiftrt:DI (match_operand:DI 1 "general_operand" "0") - (match_operand:QI 2 "general_operand" "cJ"))) - (clobber (match_dup 2))] +(define_expand "ashrdi3" + [(set (match_operand:DI 0 "register_operand" "") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')) + { + operands[2] = copy_to_mode_reg (QImode, operands[2]); + emit_insn (gen_ashrdi3_non_const_int (operands[0], operands[1], + operands[2])); + } + else + emit_insn (gen_ashrdi3_const_int (operands[0], operands[1], operands[2])); + + DONE; +}") + +(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")))] "" "* { - rtx xops[5], low[1], high[1]; + rtx xops[4], low[1], high[1]; CC_STATUS_INIT; @@ -2220,50 +2513,66 @@ xops[2] = low[0]; xops[3] = high[0]; - if (REG_P (xops[0])) /* If shift count in %cl */ + if (INTVAL (xops[0]) > 31) { - output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */ + 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 */ - output_asm_insn (AS2 (shrd%L2,%3,%2), xops); - output_asm_insn (AS2 (sar%L3,%0,%3), xops); - output_asm_insn (AS2 (shrd%L2,%3,%2), xops); + if (INTVAL (xops[0]) > 32) + { + xops[0] = GEN_INT (INTVAL (xops[0]) - 32); + output_asm_insn (AS2 (sar%L2,%0,%2), xops); /* Remaining shift */ + } + } + else + { + output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops); output_asm_insn (AS2 (sar%L3,%0,%3), xops); + } - xops[1] = gen_rtx (CONST_INT, VOIDmode, 7); /* shift count & 1 */ + RET; +}") - output_asm_insn (AS2 (shr%B0,%1,%0), xops); +(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))] + "" + "* +{ + rtx xops[4], low[1], high[1]; - output_asm_insn (AS2 (shrd%L2,%3,%2), xops); - output_asm_insn (AS2 (sar%L3,%0,%3), xops); - } - else if (GET_CODE (xops[0]) == CONST_INT) - { - if (INTVAL (xops[0]) > 31) - { - xops[1] = gen_rtx (CONST_INT, VOIDmode, 31); - output_asm_insn (AS2 (mov%L2,%3,%2), xops); - output_asm_insn (AS2 (sar%L3,%1,%3), xops); /* shift by 32 */ + CC_STATUS_INIT; - if (INTVAL (xops[0]) > 32) - { - xops[0] = gen_rtx (CONST_INT, VOIDmode, INTVAL (xops[0]) - 32); + split_di (operands, 1, low, high); + xops[0] = operands[2]; + xops[1] = const1_rtx; + 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 (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 (sar%2,%0,%2), xops); /* Remaining shift */ - } - } - else - { - output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops); - output_asm_insn (AS2 (sar%L3,%0,%3), xops); - } - } RET; }") (define_insn "ashrsi3" [(set (match_operand:SI 0 "general_operand" "=rm") (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "cI")))] + (match_operand:SI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2276,7 +2585,7 @@ (define_insn "ashrhi3" [(set (match_operand:HI 0 "general_operand" "=rm") (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") - (match_operand:HI 2 "general_operand" "cI")))] + (match_operand:HI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2289,7 +2598,7 @@ (define_insn "ashrqi3" [(set (match_operand:QI 0 "general_operand" "=qm") (ashiftrt:QI (match_operand:QI 1 "general_operand" "0") - (match_operand:QI 2 "general_operand" "cI")))] + (match_operand:QI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2303,15 +2612,34 @@ ;; See comment above `ashldi3' about how this works. -(define_insn "lshrdi3" - [(set (match_operand:DI 0 "general_operand" "=&r") - (lshiftrt:DI (match_operand:DI 1 "general_operand" "0") - (match_operand:QI 2 "general_operand" "cJ"))) - (clobber (match_dup 2))] +(define_expand "lshrdi3" + [(set (match_operand:DI 0 "register_operand" "") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) != CONST_INT + || ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')) + { + operands[2] = copy_to_mode_reg (QImode, operands[2]); + emit_insn (gen_lshrdi3_non_const_int (operands[0], operands[1], + operands[2])); + } + else + emit_insn (gen_lshrdi3_const_int (operands[0], operands[1], operands[2])); + + DONE; +}") + +(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")))] "" "* { - rtx xops[5], low[1], high[1]; + rtx xops[4], low[1], high[1]; CC_STATUS_INIT; @@ -2321,49 +2649,65 @@ xops[2] = low[0]; xops[3] = high[0]; - if (REG_P (xops[0])) /* If shift count in %cl */ + if (INTVAL (xops[0]) > 31) { - output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */ + output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */ + output_asm_insn (AS2 (xor%L3,%3,%3), xops); - output_asm_insn (AS2 (shrd%L2,%3,%2), xops); - output_asm_insn (AS2 (shr%L3,%0,%3), xops); - output_asm_insn (AS2 (shrd%L2,%3,%2), xops); + if (INTVAL (xops[0]) > 32) + { + xops[0] = GEN_INT (INTVAL (xops[0]) - 32); + output_asm_insn (AS2 (shr%L2,%0,%2), xops); /* Remaining shift */ + } + } + else + { + output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops); output_asm_insn (AS2 (shr%L3,%0,%3), xops); + } - xops[1] = gen_rtx (CONST_INT, VOIDmode, 7); /* shift count & 1 */ + RET; +}") - output_asm_insn (AS2 (shr%B0,%1,%0), xops); +(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))] + "" + "* +{ + rtx xops[4], low[1], high[1]; - output_asm_insn (AS2 (shrd%L2,%3,%2), xops); - output_asm_insn (AS2 (shr%L3,%0,%3), xops); - } - else if (GET_CODE (xops[0]) == CONST_INT) - { - if (INTVAL (xops[0]) > 31) - { - output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */ - output_asm_insn (AS2 (xor%L3,%3,%3), xops); + CC_STATUS_INIT; - if (INTVAL (xops[0]) > 32) - { - xops[0] = gen_rtx (CONST_INT, VOIDmode, INTVAL (xops[0]) - 32); + split_di (operands, 1, low, high); + xops[0] = operands[2]; + xops[1] = const1_rtx; + 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); + + 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 (shr%2,%0,%2), xops); /* Remaining shift */ - } - } - else - { - output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops); - output_asm_insn (AS2 (shr%L3,%0,%3), xops); - } - } RET; }") (define_insn "lshrsi3" [(set (match_operand:SI 0 "general_operand" "=rm") (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "cI")))] + (match_operand:SI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2376,7 +2720,7 @@ (define_insn "lshrhi3" [(set (match_operand:HI 0 "general_operand" "=rm") (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") - (match_operand:HI 2 "general_operand" "cI")))] + (match_operand:HI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2389,7 +2733,7 @@ (define_insn "lshrqi3" [(set (match_operand:QI 0 "general_operand" "=qm") (lshiftrt:QI (match_operand:QI 1 "general_operand" "0") - (match_operand:QI 2 "general_operand" "cI")))] + (match_operand:QI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2404,7 +2748,7 @@ (define_insn "rotlsi3" [(set (match_operand:SI 0 "general_operand" "=rm") (rotate:SI (match_operand:SI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "cI")))] + (match_operand:SI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2417,7 +2761,7 @@ (define_insn "rotlhi3" [(set (match_operand:HI 0 "general_operand" "=rm") (rotate:HI (match_operand:HI 1 "general_operand" "0") - (match_operand:HI 2 "general_operand" "cI")))] + (match_operand:HI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2430,7 +2774,7 @@ (define_insn "rotlqi3" [(set (match_operand:QI 0 "general_operand" "=qm") (rotate:QI (match_operand:QI 1 "general_operand" "0") - (match_operand:QI 2 "general_operand" "cI")))] + (match_operand:QI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2443,7 +2787,7 @@ (define_insn "rotrsi3" [(set (match_operand:SI 0 "general_operand" "=rm") (rotatert:SI (match_operand:SI 1 "general_operand" "0") - (match_operand:SI 2 "general_operand" "cI")))] + (match_operand:SI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2456,7 +2800,7 @@ (define_insn "rotrhi3" [(set (match_operand:HI 0 "general_operand" "=rm") (rotatert:HI (match_operand:HI 1 "general_operand" "0") - (match_operand:HI 2 "general_operand" "cI")))] + (match_operand:HI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2469,7 +2813,7 @@ (define_insn "rotrqi3" [(set (match_operand:QI 0 "general_operand" "=qm") (rotatert:QI (match_operand:QI 1 "general_operand" "0") - (match_operand:QI 2 "general_operand" "cI")))] + (match_operand:QI 2 "nonmemory_operand" "cI")))] "" "* { @@ -2496,11 +2840,9 @@ if (GET_CODE (operands[3]) == CONST_INT) { unsigned int mask = (1 << INTVAL (operands[1])) - 1; - operands[1] = gen_rtx (CONST_INT, VOIDmode, - ~(mask << INTVAL (operands[2]))); + operands[1] = GEN_INT (~(mask << INTVAL (operands[2]))); output_asm_insn (AS2 (and%L0,%1,%0), operands); - operands[3] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[3]) << INTVAL (operands[2])); + operands[3] = GEN_INT (INTVAL (operands[3]) << INTVAL (operands[2])); output_asm_insn (AS2 (or%L0,%3,%0), operands); } else @@ -2509,8 +2851,7 @@ if (INTVAL (operands[2])) output_asm_insn (AS2 (ror%L0,%2,%0), operands); output_asm_insn (AS3 (shrd%L0,%1,%3,%0), operands); - operands[2] = gen_rtx (CONST_INT, VOIDmode, - BITS_PER_WORD + operands[2] = GEN_INT (BITS_PER_WORD - INTVAL (operands[1]) - INTVAL (operands[2])); if (INTVAL (operands[2])) output_asm_insn (AS2 (ror%L0,%2,%0), operands); @@ -2571,9 +2912,9 @@ (define_insn "" [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+rm") (const_int 1) - (match_operand:SI 2 "nonimmediate_operand" "r")) - (match_operand:SI 3 "immediate_operand" "i"))] - "! TARGET_486" + (match_operand:SI 2 "general_operand" "r")) + (match_operand:SI 3 "const_int_operand" "n"))] + "! TARGET_486 && GET_CODE (operands[2]) != CONST_INT" "* { CC_STATUS_INIT; @@ -2591,7 +2932,7 @@ (xor:SI (ashift:SI (const_int 1) (match_operand:SI 1 "general_operand" "r")) (match_dup 0)))] - "! TARGET_486" + "! TARGET_486 && GET_CODE (operands[1]) != CONST_INT" "* { CC_STATUS_INIT; @@ -2622,112 +2963,134 @@ ;; i486, it is faster to copy a MEM to REG and then use bt, than to use ;; bt on the MEM directly. +;; ??? The first argument of a zero_extract must not be reloaded, so +;; don't allow a MEM in the operand predicate without allowing it in the +;; constraint. + +;; ??? All bets are off if operand 0 is a volatile MEM reference. + +/* (define_insn "" - [(set (cc0) (zero_extract (match_operand:QI 0 "register_operand" "q") - (const_int 1) - (match_operand:SI 1 "general_operand" "ri")))] - "" + [(set (cc0) (zero_extract (match_operand 0 "general_operand" "rm") + (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n")))] + "GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_INT + && GET_MODE_SIZE (GET_MODE (operands[0])) <= 4 + && (GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0]))" "* { - if (GET_CODE (operands[1]) == CONST_INT) - { - operands[1] = gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (operands[1])); - output_asm_insn (AS2 (test%B0,%1,%0), operands); - } - else + unsigned int mask; + + mask = ((1 << INTVAL (operands[1])) - 1) << INTVAL (operands[2]); + operands[1] = GEN_INT (mask); + + if (! REG_P (operands[0]) || QI_REG_P (operands[0])) { - operands[0] = gen_rtx (REG, SImode, REGNO (operands[0])); - cc_status.flags |= CC_Z_IN_NOT_C; - output_asm_insn (AS2 (bt%L0,%1,%0), operands); + if ((mask & ~0xff) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + return AS2 (test%B0,%1,%b0); + } + + if ((mask & ~0xff00) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + operands[1] = GEN_INT (mask >> 8); + + if (QI_REG_P (operands[0])) + return AS2 (test%B0,%1,%h0); + else + { + operands[0] = adj_offsettable_operand (operands[0], 1); + return AS2 (test%B0,%1,%b0); + } + } + + if (GET_CODE (operands[0]) == MEM && (mask & ~0xff0000) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + operands[1] = GEN_INT (mask >> 16); + operands[0] = adj_offsettable_operand (operands[0], 2); + return AS2 (test%B0,%1,%b0); + } + + if (GET_CODE (operands[0]) == MEM && (mask & ~0xff000000) == 0) + { + cc_status.flags |= CC_NOT_NEGATIVE; + operands[1] = GEN_INT (mask >> 24); + operands[0] = adj_offsettable_operand (operands[0], 3); + return AS2 (test%B0,%1,%b0); + } } - RET; -}") + if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM) + return AS2 (test%L0,%1,%0); + + return AS2 (test%L1,%0,%1); +}") +*/ (define_insn "" - [(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "m") + [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r") (const_int 1) - (match_operand:SI 1 "general_operand" "ri"))) - (clobber (match_scratch:SI 2 "=&r"))] - "" + (match_operand:SI 1 "general_operand" "r")))] + "GET_CODE (operands[1]) != CONST_INT" "* { - /* Copy memory to scratch register; pretend it was there to start with. */ - if (GET_CODE (operands[0]) == MEM) - { - output_asm_insn (AS2 (mov%L2,%0,%2), operands); - operands[0] = operands[2]; - } - if (GET_CODE (operands[1]) == CONST_INT) - { - operands[1] = gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (operands[1])); - output_asm_insn (AS2 (test%L0,%1,%0), operands); - } - else - { - operands[0] = gen_rtx (REG, SImode, REGNO (operands[0])); - cc_status.flags |= CC_Z_IN_NOT_C; - output_asm_insn (AS2 (bt%L0,%1,%0), operands); - } - RET; + cc_status.flags |= CC_Z_IN_NOT_C; + return AS2 (bt%L0,%1,%0); }") + +;; Store-flag instructions. -(define_insn "" - [(set (cc0) (zero_extract (match_operand:HI 0 "nonimmediate_operand" "r") - (const_int 1) - (match_operand:SI 1 "general_operand" "ri")))] +;; For all sCOND expanders, also expand the compare or test insn that +;; generates cc0. Generate an equality comparison if `seq' or `sne'. + +;; The 386 sCOND opcodes can write to memory. But a gcc sCOND insn may +;; not have any input reloads. A MEM write might need an input reload +;; for the address of the MEM. So don't allow MEM as the SET_DEST. + +(define_expand "seq" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (eq:QI (cc0) (const_int 0)))] "" - "* + " { - if (GET_CODE (operands[1]) == CONST_INT) - { - operands[1] = gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (operands[1])); - output_asm_insn (AS2 (test%W0,%1,%0), operands); - } + if (TARGET_IEEE_FP + && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) + operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); else - { - cc_status.flags |= CC_Z_IN_NOT_C; - output_asm_insn (AS2 (bt%W0,%1,%0), operands); - } - RET; + operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); }") (define_insn "" - [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "r") - (const_int 1) - (match_operand:SI 1 "general_operand" "ri")))] + [(set (match_operand:QI 0 "register_operand" "=q") + (eq:QI (cc0) (const_int 0)))] "" "* { - if (GET_CODE (operands[1]) == CONST_INT) - { - operands[1] = gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (operands[1])); - output_asm_insn (AS2 (test%L0,%1,%0), operands); - } + if (cc_prev_status.flags & CC_Z_IN_NOT_C) + return AS1 (setnb,%0); else - { - cc_status.flags |= CC_Z_IN_NOT_C; - output_asm_insn (AS2 (bt%L0,%1,%0), operands); - } - RET; + return AS1 (sete,%0); }") - -;; Store-flag instructions. -(define_insn "seq" - [(set (match_operand:QI 0 "general_operand" "=qm") - (eq:QI (cc0) (const_int 0)))] +(define_expand "sne" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (ne:QI (cc0) (const_int 0)))] "" - "* + " { - if (cc_prev_status.flags & CC_Z_IN_NOT_C) - return AS1 (setnb,%0); + if (TARGET_IEEE_FP + && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) + operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); else - return AS1 (sete,%0); -} -") + operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); +}") -(define_insn "sne" - [(set (match_operand:QI 0 "general_operand" "=qm") +(define_insn "" + [(set (match_operand:QI 0 "register_operand" "=q") (ne:QI (cc0) (const_int 0)))] "" "* @@ -2739,50 +3102,130 @@ } ") -(define_insn "sgt" - [(set (match_operand:QI 0 "general_operand" "=qm") +(define_expand "sgt" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") (gt:QI (cc0) (const_int 0)))] "" - "* OUTPUT_JUMP (\"setg %0\", \"seta %0\", 0); ") + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") -(define_insn "sgtu" - [(set (match_operand:QI 0 "general_operand" "=qm") +(define_insn "" + [(set (match_operand:QI 0 "register_operand" "=q") + (gt:QI (cc0) (const_int 0)))] + "" + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (sete,%0); + + OUTPUT_JUMP (\"setg %0\", \"seta %0\", NULL_PTR); +}") + +(define_expand "sgtu" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (gtu:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" + [(set (match_operand:QI 0 "register_operand" "=q") (gtu:QI (cc0) (const_int 0)))] "" "* return \"seta %0\"; ") -(define_insn "slt" - [(set (match_operand:QI 0 "general_operand" "=qm") +(define_expand "slt" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") (lt:QI (cc0) (const_int 0)))] "" - "* OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %0\"); ") + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") -(define_insn "sltu" - [(set (match_operand:QI 0 "general_operand" "=qm") +(define_insn "" + [(set (match_operand:QI 0 "register_operand" "=q") + (lt:QI (cc0) (const_int 0)))] + "" + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (sete,%0); + + OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %0\"); +}") + +(define_expand "sltu" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (ltu:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" + [(set (match_operand:QI 0 "register_operand" "=q") (ltu:QI (cc0) (const_int 0)))] "" "* return \"setb %0\"; ") -(define_insn "sge" - [(set (match_operand:QI 0 "general_operand" "=qm") +(define_expand "sge" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") (ge:QI (cc0) (const_int 0)))] "" - "* OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %0\"); ") + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") -(define_insn "sgeu" - [(set (match_operand:QI 0 "general_operand" "=qm") +(define_insn "" + [(set (match_operand:QI 0 "register_operand" "=q") + (ge:QI (cc0) (const_int 0)))] + "" + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (sete,%0); + + OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %0\"); +}") + +(define_expand "sgeu" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (geu:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" + [(set (match_operand:QI 0 "register_operand" "=q") (geu:QI (cc0) (const_int 0)))] "" "* return \"setae %0\"; ") -(define_insn "sle" - [(set (match_operand:QI 0 "general_operand" "=qm") +(define_expand "sle" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") (le:QI (cc0) (const_int 0)))] "" - "* OUTPUT_JUMP (\"setle %0\", \"setbe %0\", 0); ") + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") -(define_insn "sleu" - [(set (match_operand:QI 0 "general_operand" "=qm") +(define_insn "" + [(set (match_operand:QI 0 "register_operand" "=q") + (le:QI (cc0) (const_int 0)))] + "" + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (setb,%0); + + OUTPUT_JUMP (\"setle %0\", \"setbe %0\", NULL_PTR); +}") + +(define_expand "sleu" + [(match_dup 1) + (set (match_operand:QI 0 "register_operand" "") + (leu:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" + [(set (match_operand:QI 0 "register_operand" "=q") (leu:QI (cc0) (const_int 0)))] "" "* return \"setbe %0\"; ") @@ -2790,7 +3233,27 @@ ;; Basic conditional jump instructions. ;; We ignore the overflow flag for signed branch instructions. -(define_insn "beq" +;; For all bCOND expanders, also expand the compare or test insn that +;; generates cc0. Generate an equality comparison if `beq' or `bne'. + +(define_expand "beq" + [(match_dup 1) + (set (pc) + (if_then_else (eq (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (TARGET_IEEE_FP + && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) + operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); + else + operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); +}") + +(define_insn "" [(set (pc) (if_then_else (eq (cc0) (const_int 0)) @@ -2805,7 +3268,24 @@ return \"je %l0\"; }") -(define_insn "bne" +(define_expand "bne" + [(match_dup 1) + (set (pc) + (if_then_else (ne (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + " +{ + if (TARGET_IEEE_FP + && GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT) + operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1); + else + operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); +}") + +(define_insn "" [(set (pc) (if_then_else (ne (cc0) (const_int 0)) @@ -2820,16 +3300,42 @@ return \"jne %l0\"; }") -(define_insn "bgt" +(define_expand "bgt" + [(match_dup 1) + (set (pc) + (if_then_else (gt (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" [(set (pc) (if_then_else (gt (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" - "*OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0)") + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (je,%l0); -(define_insn "bgtu" + OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", NULL_PTR); +}") + +(define_expand "bgtu" + [(match_dup 1) + (set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) @@ -2838,35 +3344,15 @@ "" "ja %l0") -;; There is no jump insn to check for `<' on IEEE floats. -;; Page 17-80 in the 80387 manual says jb, but that's wrong; -;; jb checks for `not >='. So swap the operands and do `>'. (define_expand "blt" - [(set (pc) + [(match_dup 1) + (set (pc) (if_then_else (lt (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - rtx prev = get_last_insn_anywhere (); - rtx body = PATTERN (prev); - rtx comp; - if (GET_CODE (body) == SET) - comp = SET_SRC (body); - else - comp = SET_SRC (XVECEXP (body, 0, 0)); - - if (GET_CODE (comp) == COMPARE - ? GET_MODE_CLASS (GET_MODE (XEXP (comp, 0))) == MODE_FLOAT - : GET_MODE_CLASS (GET_MODE (comp)) == MODE_FLOAT) - { - reverse_comparison (prev); - emit_insn (gen_bgt (operands[0])); - DONE; - } -}") + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") (define_insn "" [(set (pc) @@ -2875,9 +3361,25 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "*OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\")") + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (je,%l0); + + OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\"); +}") + +(define_expand "bltu" + [(match_dup 1) + (set (pc) + (if_then_else (ltu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") -(define_insn "bltu" +(define_insn "" [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) @@ -2886,16 +3388,42 @@ "" "jb %l0") -(define_insn "bge" +(define_expand "bge" + [(match_dup 1) + (set (pc) + (if_then_else (ge (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" [(set (pc) (if_then_else (ge (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" - "*OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\")") + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (je,%l0); + + OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\"); +}") -(define_insn "bgeu" +(define_expand "bgeu" + [(match_dup 1) + (set (pc) + (if_then_else (geu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" [(set (pc) (if_then_else (geu (cc0) (const_int 0)) @@ -2904,33 +3432,15 @@ "" "jae %l0") -;; See comment on `blt', above. (define_expand "ble" - [(set (pc) + [(match_dup 1) + (set (pc) (if_then_else (le (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - rtx prev = get_last_insn_anywhere (); - rtx body = PATTERN (prev); - rtx comp; - if (GET_CODE (body) == SET) - comp = SET_SRC (body); - else - comp = SET_SRC (XVECEXP (body, 0, 0)); - - if (GET_CODE (comp) == COMPARE - ? GET_MODE_CLASS (GET_MODE (XEXP (comp, 0))) == MODE_FLOAT - : GET_MODE_CLASS (GET_MODE (comp)) == MODE_FLOAT) - { - reverse_comparison (prev); - emit_insn (gen_bge (operands[0])); - DONE; - } -}") + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") (define_insn "" [(set (pc) @@ -2939,9 +3449,25 @@ (label_ref (match_operand 0 "" "")) (pc)))] "" - "*OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0) ") + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (jb,%l0); + + OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", NULL_PTR); +}") + +(define_expand "bleu" + [(match_dup 1) + (set (pc) + (if_then_else (leu (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") -(define_insn "bleu" +(define_insn "" [(set (pc) (if_then_else (leu (cc0) (const_int 0)) @@ -2989,7 +3515,13 @@ (pc) (label_ref (match_operand 0 "" ""))))] "" - "*OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", 0) ") + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (jne,%l0); + + OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", NULL_PTR); +}") (define_insn "" [(set (pc) @@ -3007,8 +3539,13 @@ (pc) (label_ref (match_operand 0 "" ""))))] "" - "*OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\") -") + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (jne,%l0); + + OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\"); +}") (define_insn "" [(set (pc) @@ -3026,7 +3563,13 @@ (pc) (label_ref (match_operand 0 "" ""))))] "" - "*OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\")") + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (jne,%l0); + + OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\"); +}") (define_insn "" [(set (pc) @@ -3044,7 +3587,13 @@ (pc) (label_ref (match_operand 0 "" ""))))] "" - "*OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0)") + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (jae,%l0); + + OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", NULL_PTR); +}") (define_insn "" [(set (pc) @@ -3079,31 +3628,29 @@ ;; Emit code here to do the range checking and make the index zero based. (define_expand "casesi" - [(parallel + [(set (match_dup 5) + (minus:SI (match_operand:SI 0 "general_operand" "") + (match_operand:SI 1 "general_operand" ""))) + (set (cc0) + (compare:CC (match_dup 5) + (match_operand:SI 2 "general_operand" ""))) + (set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 4 "" "")) + (pc))) + (parallel [(set (pc) - (if_then_else (leu (minus:SI - (match_operand:SI 0 "general_operand" "") - (match_operand:SI 1 "const_int_operand" "")) - (match_operand:SI 2 "const_int_operand" "")) - (plus:SI (mem:SI (plus:SI (pc) - (minus:SI (match_dup 0) - (match_dup 1)))) - (label_ref (match_operand 3 "" ""))) - (pc))) - (use (label_ref (match_operand 4 "" ""))) - (clobber (match_scratch:SI 5 ""))])] + (minus:SI (reg:SI 3) + (mem:SI (plus:SI (mult:SI (match_dup 5) + (const_int 4)) + (label_ref (match_operand 3 "" "")))))) + (clobber (match_scratch:SI 6 ""))])] "flag_pic" " { - rtx reg = gen_reg_rtx (SImode); - + operands[5] = gen_reg_rtx (SImode); current_function_uses_pic_offset_table = 1; - - emit_insn (gen_subsi3 (reg, operands[0], operands[1])); - emit_insn (gen_cmpsi (reg, operands[2])); - emit_jump_insn (gen_bgtu (operands[4])); - operands[0] = reg; - operands[1] = CONST0_RTX (SImode); }") ;; Implement a casesi insn. @@ -3137,30 +3684,25 @@ (define_insn "" [(set (pc) - (if_then_else (leu (minus:SI - (match_operand:SI 0 "general_operand" "r") - (match_operand:SI 1 "const_int_operand" "i")) - (match_operand:SI 2 "const_int_operand" "i")) - (plus:SI (mem:SI (plus:SI (pc) - (minus:SI (match_dup 0) - (match_dup 1)))) - (label_ref (match_operand 3 "" ""))) - (pc))) - (use (label_ref (match_operand 4 "" ""))) - (clobber (match_scratch:SI 5 "=&r"))] + (minus:SI (reg:SI 3) + (mem:SI (plus:SI + (mult:SI (match_operand:SI 0 "register_operand" "r") + (const_int 4)) + (label_ref (match_operand 1 "" "")))))) + (clobber (match_scratch:SI 2 "=&r"))] "" "* { rtx xops[4]; - xops[0] = pic_offset_table_rtx; - xops[1] = operands[5]; - xops[2] = operands[3]; - xops[3] = operands[0]; - - output_asm_insn (AS2 (mov%L1,%0,%1), xops); - output_asm_insn (\"sub%L1 %l2@GOTOFF(%0,%3,4),%1\", xops); - output_asm_insn (AS1 (jmp,%*%1), xops); + xops[0] = operands[0]; + xops[1] = operands[1]; + xops[2] = operands[2]; + xops[3] = pic_offset_table_rtx; + + 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); RET; }") @@ -3196,8 +3738,15 @@ "" " { + rtx addr; + if (flag_pic) current_function_uses_pic_offset_table = 1; + + /* With half-pic, force the address into a register. */ + addr = XEXP (operands[0], 0); + if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr)) + XEXP (operands[0], 0) = force_reg (Pmode, addr); }") (define_insn "" @@ -3223,7 +3772,7 @@ (match_operand:SI 1 "general_operand" "g")) (set (reg:SI 7) (plus:SI (reg:SI 7) (match_operand:SI 3 "immediate_operand" "i")))] - "" + "!HALF_PIC_P ()" "call %P0") (define_expand "call" @@ -3233,8 +3782,15 @@ "" " { + rtx addr; + if (flag_pic) current_function_uses_pic_offset_table = 1; + + /* With half-pic, force the address into a register. */ + addr = XEXP (operands[0], 0); + if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr)) + XEXP (operands[0], 0) = force_reg (Pmode, addr); }") (define_insn "" @@ -3258,7 +3814,7 @@ [(call (mem:QI (match_operand:SI 0 "symbolic_operand" "")) (match_operand:SI 1 "general_operand" "g"))] ;; Operand 1 not used on the i386. - "" + "!HALF_PIC_P ()" "call %P0") ;; Call subroutine, returning value in operand 0 @@ -3274,8 +3830,15 @@ "" " { + rtx addr; + if (flag_pic) current_function_uses_pic_offset_table = 1; + + /* With half-pic, force the address into a register. */ + addr = XEXP (operands[1], 0); + if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr)) + XEXP (operands[1], 0) = force_reg (Pmode, addr); }") (define_insn "" @@ -3305,7 +3868,7 @@ (match_operand:SI 2 "general_operand" "g"))) (set (reg:SI 7) (plus:SI (reg:SI 7) (match_operand:SI 4 "immediate_operand" "i")))] - "" + "!HALF_PIC_P ()" "call %P1") (define_expand "call_value" @@ -3316,8 +3879,15 @@ "" " { + rtx addr; + if (flag_pic) current_function_uses_pic_offset_table = 1; + + /* With half-pic, force the address into a register. */ + addr = XEXP (operands[1], 0); + if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr)) + XEXP (operands[1], 0) = force_reg (Pmode, addr); }") (define_insn "" @@ -3345,7 +3915,7 @@ (call (mem:QI (match_operand:SI 1 "symbolic_operand" "")) (match_operand:SI 2 "general_operand" "g")))] ;; Operand 2 not used on the i386. - "" + "!HALF_PIC_P ()" "call %P1") ;; Insn emitted into the body of a function to return from a function. @@ -3367,58 +3937,61 @@ "nop") (define_expand "movstrsi" - [(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" "")) - (mem:BLK (match_operand:BLK 1 "general_operand" ""))) - (use (match_operand:SI 2 "immediate_operand" "")) - (use (match_operand:SI 3 "immediate_operand" "")) - (set (match_operand:SI 4 "register_operand" "") - (const_int 0)) - (set (match_dup 0) - (plus:SI (match_dup 0) - (match_dup 2))) - (set (match_dup 1) - (plus:SI (match_dup 1) - (match_dup 2)))])] + [(parallel [(set (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_operand" "")) + (use (match_operand:SI 2 "const_int_operand" "")) + (use (match_operand:SI 3 "const_int_operand" "")) + (clobber (match_scratch:SI 4 "")) + (clobber (match_dup 5)) + (clobber (match_dup 6))])] "" " { + rtx addr0, addr1; + if (GET_CODE (operands[2]) != CONST_INT) FAIL; - operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); - operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); - operands[4] = gen_reg_rtx (SImode); + + addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); + + operands[5] = addr0; + operands[6] = addr1; + + operands[0] = gen_rtx (MEM, BLKmode, addr0); + operands[1] = gen_rtx (MEM, BLKmode, addr1); }") +;; It might seem that operands 0 & 1 could use predicate register_operand. +;; But strength reduction might offset the MEM expression. So we let +;; reload put the address into %edi & %esi. + (define_insn "" - [(set (mem:BLK (match_operand:SI 0 "register_operand" "D")) - (mem:BLK (match_operand:SI 1 "register_operand" "S"))) - (use (match_operand:SI 2 "immediate_operand" "n")) + [(set (mem:BLK (match_operand:SI 0 "address_operand" "D")) + (mem:BLK (match_operand:SI 1 "address_operand" "S"))) + (use (match_operand:SI 2 "const_int_operand" "n")) (use (match_operand:SI 3 "immediate_operand" "i")) - (set (match_operand:SI 4 "register_operand" "c") - (const_int 0)) - (set (match_operand:SI 5 "register_operand" "=0") - (plus:SI (match_dup 0) - (match_dup 2))) - (set (match_operand:SI 7 "register_operand" "=1") - (plus:SI (match_dup 1) - (match_dup 2)))] + (clobber (match_scratch:SI 4 "=&c")) + (clobber (match_dup 0)) + (clobber (match_dup 1))] "" "* { rtx xops[2]; + output_asm_insn (\"cld\", operands); if (GET_CODE (operands[2]) == CONST_INT) { if (INTVAL (operands[2]) & ~0x03) { - xops[0] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) >> 2); - xops[1] = gen_rtx (REG, SImode, 2); + xops[0] = GEN_INT ((INTVAL (operands[2]) >> 2) & 0x3fffffff); + xops[1] = operands[4]; output_asm_insn (AS2 (mov%L1,%0,%1), xops); #ifdef INTEL_SYNTAX output_asm_insn (\"rep movsd\", xops); #else - output_asm_insn (\"rep\;movs%L1\", xops); + output_asm_insn (\"rep\;movsl\", xops); #endif } if (INTVAL (operands[2]) & 0x02) @@ -3432,28 +4005,47 @@ }") (define_expand "cmpstrsi" - [(parallel [(set (match_operand:QI 0 "general_operand" "") - (compare - (mem:BLK (match_operand:BLK 1 "general_operand" "")) - (mem:BLK (match_operand:BLK 2 "general_operand" "")))) + [(parallel [(set (match_operand:SI 0 "general_operand" "") + (compare:CC (match_operand:BLK 1 "general_operand" "") + (match_operand:BLK 2 "general_operand" ""))) (use (match_operand:SI 3 "general_operand" "")) (use (match_operand:SI 4 "immediate_operand" "")) - (clobber (match_dup 1)) - (clobber (match_dup 2)) + (clobber (match_dup 5)) + (clobber (match_dup 6)) (clobber (match_dup 3))])] "" " { - operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); - operands[2] = copy_to_mode_reg (SImode, XEXP (operands[2], 0)); + rtx addr1, addr2; + + addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); + addr2 = copy_to_mode_reg (Pmode, XEXP (operands[2], 0)); operands[3] = copy_to_mode_reg (SImode, operands[3]); + + operands[5] = addr1; + operands[6] = addr2; + + operands[1] = gen_rtx (MEM, BLKmode, addr1); + operands[2] = gen_rtx (MEM, BLKmode, addr2); + }") +;; memcmp recognizers. The `cmpsb' opcode does nothing if the count is +;; zero. Emit extra code to make sure that a zero-length compare is EQ. + +;; It might seem that operands 0 & 1 could use predicate register_operand. +;; But strength reduction might offset the MEM expression. So we let +;; reload put the address into %edi & %esi. + +;; ??? Most comparisons have a constant length, and it's therefore +;; possible to know that the length is non-zero, and to avoid the extra +;; code to handle zero-length compares. + (define_insn "" - [(set (match_operand:QI 0 "general_operand" "=q") - (compare (mem:BLK (match_operand:SI 1 "general_operand" "D")) - (mem:BLK (match_operand:SI 2 "general_operand" "S")))) - (use (match_operand:SI 3 "general_operand" "c")) + [(set (match_operand:SI 0 "general_operand" "=&r") + (compare:CC (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")) (use (match_operand:SI 4 "immediate_operand" "i")) (clobber (match_dup 1)) (clobber (match_dup 2)) @@ -3461,32 +4053,53 @@ "" "* { - rtx xops[3]; + rtx xops[4], label; + + label = gen_label_rtx (); + output_asm_insn (\"cld\", operands); + output_asm_insn (AS2 (xor%L0,%0,%0), operands); output_asm_insn (\"repz\;cmps%B2\", operands); + 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 (mov%B0,%1,%b0), xops); - output_asm_insn (AS2 (sub%B0,%2,%b0), xops); + 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); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (label)); RET; }") (define_insn "" [(set (cc0) - (compare (mem:BLK (match_operand:SI 0 "general_operand" "D")) - (mem:BLK (match_operand:SI 1 "general_operand" "S")))) - (use (match_operand:SI 2 "general_operand" "c")) + (compare:CC (mem:BLK (match_operand:SI 0 "address_operand" "S")) + (mem:BLK (match_operand:SI 1 "address_operand" "D")))) + (use (match_operand:SI 2 "register_operand" "c")) (use (match_operand:SI 3 "immediate_operand" "i")) (clobber (match_dup 0)) (clobber (match_dup 1)) (clobber (match_dup 2))] "" - "repz\;cmps%B2") + "* +{ + rtx xops[2]; + + cc_status.flags |= CC_NOT_SIGNED; + + xops[0] = gen_rtx (REG, QImode, 0); + xops[1] = CONST0_RTX (QImode); + + output_asm_insn (\"cld\", operands); + output_asm_insn (AS2 (test%B0,%1,%0), xops); + return \"repz\;cmps%B2\"; +}") (define_expand "ffssi2" [(set (match_dup 2) @@ -3609,6 +4222,47 @@ "TARGET_80387" "* return (char *) output_387_binary_op (insn, operands);") +(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: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)))] + "" + " +{ + operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); + operands[4] = gen_reg_rtx (SImode); + operands[5] = gen_reg_rtx (SImode); +}") + +;; It might seem that operands 0 & 1 could use predicate register_operand. +;; But strength reduction might offset the MEM expression. So we let +;; reload put the address into %edi & %esi. + +(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:SI 3 "immediate_operand" "i")] 0)) + (clobber (match_dup 1))] + "" + "* +{ + rtx xops[2]; + + xops[0] = operands[0]; + xops[1] = constm1_rtx; + output_asm_insn (\"cld\", operands); + output_asm_insn (AS2 (mov%L0,%1,%0), xops); + return \"repnz\;scas%B2\"; +}") + ;;- Local variables: ;;- mode:emacs-lisp ;;- comment-start: ";;- "