--- gcc/config/i386.md 2018/04/24 17:51:37 1.1 +++ gcc/config/i386.md 2018/04/24 18:00:07 1.1.1.3 @@ -19,37 +19,41 @@ ;; 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. - ;; "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 +62,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 +79,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 +103,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 +127,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 +222,23 @@ return AS2 (cmp%L0,%1,%0); }") -(define_insn "cmphi" +(define_expand "cmpsi" + [(set (cc0) + (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 (match_operand:HI 0 "nonimmediate_operand" "mr,ri") - (match_operand:HI 1 "general_operand" "ri,mr")))] + (compare:CC (match_operand:HI 0 "nonimmediate_operand" "mr,ri") + (match_operand:HI 1 "general_operand" "ri,mr")))] "" "* { @@ -171,10 +250,23 @@ return AS2 (cmp%W0,%1,%0); }") -(define_insn "cmpqi" +(define_expand "cmphi" [(set (cc0) - (compare (match_operand:QI 0 "nonimmediate_operand" "qn,mq") - (match_operand:QI 1 "general_operand" "qm,nq")))] + (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:CC (match_operand:QI 0 "nonimmediate_operand" "qn,mq") + (match_operand:QI 1 "general_operand" "qm,nq")))] "" "* { @@ -186,96 +278,199 @@ 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])) + && ! NON_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) { + cc_status.flags |= CC_NOT_NEGATIVE; operands[1] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) >> 8); - return AS2 (test%B0,%1,%h0); + + 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_rtx (CONST_INT, VOIDmode, + 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_rtx (CONST_INT, VOIDmode, + (INTVAL (operands[1]) >> 24) & 0xff); + + operands[0] = adj_offsettable_operand (operands[0], 3); + return AS2 (test%B0,%1,%b0); } } @@ -287,18 +482,18 @@ (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])) + && ! NON_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); @@ -308,13 +503,18 @@ 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); + + 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); + } } } @@ -747,47 +947,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. @@ -1005,11 +1164,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 +1177,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 +1194,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 +1280,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" "") @@ -1448,7 +1615,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")) @@ -1860,7 +2027,7 @@ CC_STATUS_INIT; if (INTVAL (operands[2]) == 0xff) - return AS1 (not%B0,%0); + return AS1 (not%B0,%b0); return AS2 (xor%B0,%2,%b0); } @@ -1901,7 +2068,7 @@ 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); } @@ -2074,11 +2241,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 +2278,58 @@ 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_rtx (CONST_INT, VOIDmode, 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_rtx (CONST_INT, VOIDmode, 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 +2340,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")))] "" "* { @@ -2171,7 +2373,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 +2389,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 +2404,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 +2441,67 @@ 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_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 */ - 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_rtx (CONST_INT, VOIDmode, INTVAL (xops[0]) - 32); + + 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); + } - 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_rtx (CONST_INT, VOIDmode, 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 +2514,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 +2527,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 +2541,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 +2578,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 */ + 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_rtx (CONST_INT, VOIDmode, INTVAL (xops[0]) - 32); + + 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); + } - 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_rtx (CONST_INT, VOIDmode, 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 +2650,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 +2663,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 +2678,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 +2691,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 +2704,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 +2717,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 +2730,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 +2743,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")))] "" "* { @@ -2571,9 +2845,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 +2865,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,98 +2896,41 @@ ;; i486, it is faster to copy a MEM to REG and then use bt, than to use ;; bt on the MEM directly. -(define_insn "" - [(set (cc0) (zero_extract (match_operand:QI 0 "register_operand" "q") - (const_int 1) - (match_operand:SI 1 "general_operand" "ri")))] - "" - "* -{ - 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 - { - 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; -}") +;; ??? 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. (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")))] - "" - "* -{ - 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); - } - else - { - cc_status.flags |= CC_Z_IN_NOT_C; - output_asm_insn (AS2 (bt%W0,%1,%0), operands); - } - RET; -}") +;; For all sCOND expanders, also expand the compare or test insn that +;; generates cc0. Generate an equality comparison if `seq' or `sne'. -(define_insn "" - [(set (cc0) (zero_extract (match_operand:SI 0 "nonimmediate_operand" "r") - (const_int 1) - (match_operand:SI 1 "general_operand" "ri")))] +(define_expand "seq" + [(match_dup 1) + (set (match_operand:QI 0 "general_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%L0,%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%L0,%1,%0), operands); - } - RET; + operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); }") - -;; Store-flag instructions. -(define_insn "seq" +(define_insn "" [(set (match_operand:QI 0 "general_operand" "=qm") (eq:QI (cc0) (const_int 0)))] "" @@ -2723,10 +2940,23 @@ return AS1 (setnb,%0); else return AS1 (sete,%0); -} -") +}") + +(define_expand "sne" + [(match_dup 1) + (set (match_operand:QI 0 "general_operand" "") + (ne:QI (cc0) (const_int 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 + operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1); +}") -(define_insn "sne" +(define_insn "" [(set (match_operand:QI 0 "general_operand" "=qm") (ne:QI (cc0) (const_int 0)))] "" @@ -2739,49 +2969,129 @@ } ") -(define_insn "sgt" +(define_expand "sgt" + [(match_dup 1) + (set (match_operand:QI 0 "general_operand" "") + (gt:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" [(set (match_operand:QI 0 "general_operand" "=qm") (gt:QI (cc0) (const_int 0)))] "" - "* OUTPUT_JUMP (\"setg %0\", \"seta %0\", 0); ") + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (sete,%0); + + OUTPUT_JUMP (\"setg %0\", \"seta %0\", 0); +}") + +(define_expand "sgtu" + [(match_dup 1) + (set (match_operand:QI 0 "general_operand" "") + (gtu:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") -(define_insn "sgtu" +(define_insn "" [(set (match_operand:QI 0 "general_operand" "=qm") (gtu:QI (cc0) (const_int 0)))] "" "* return \"seta %0\"; ") -(define_insn "slt" +(define_expand "slt" + [(match_dup 1) + (set (match_operand:QI 0 "general_operand" "") + (lt:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" [(set (match_operand:QI 0 "general_operand" "=qm") (lt:QI (cc0) (const_int 0)))] "" - "* OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %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 "general_operand" "") + (ltu:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") -(define_insn "sltu" +(define_insn "" [(set (match_operand:QI 0 "general_operand" "=qm") (ltu:QI (cc0) (const_int 0)))] "" "* return \"setb %0\"; ") -(define_insn "sge" +(define_expand "sge" + [(match_dup 1) + (set (match_operand:QI 0 "general_operand" "") + (ge:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" [(set (match_operand:QI 0 "general_operand" "=qm") (ge:QI (cc0) (const_int 0)))] "" - "* OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %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 "general_operand" "") + (geu:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") -(define_insn "sgeu" +(define_insn "" [(set (match_operand:QI 0 "general_operand" "=qm") (geu:QI (cc0) (const_int 0)))] "" "* return \"setae %0\"; ") -(define_insn "sle" +(define_expand "sle" + [(match_dup 1) + (set (match_operand:QI 0 "general_operand" "") + (le:QI (cc0) (const_int 0)))] + "" + "operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);") + +(define_insn "" [(set (match_operand:QI 0 "general_operand" "=qm") (le:QI (cc0) (const_int 0)))] "" - "* OUTPUT_JUMP (\"setle %0\", \"setbe %0\", 0); ") + "* +{ + if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)) + return AS1 (setb,%0); + + OUTPUT_JUMP (\"setle %0\", \"setbe %0\", 0); +}") -(define_insn "sleu" +(define_expand "sleu" + [(match_dup 1) + (set (match_operand:QI 0 "general_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 "general_operand" "=qm") (leu:QI (cc0) (const_int 0)))] "" @@ -2790,7 +3100,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 +3135,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 +3167,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); + + OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", 0); +}") + +(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 "bgtu" +(define_insn "" [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) @@ -2838,35 +3211,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 +3228,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 +3255,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_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 "bgeu" +(define_insn "" [(set (pc) (if_then_else (geu (cc0) (const_int 0)) @@ -2904,33 +3299,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 +3316,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\", 0); +}") + +(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 +3382,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\", 0); +}") (define_insn "" [(set (pc) @@ -3007,8 +3406,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 +3430,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 +3454,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\", 0); +}") (define_insn "" [(set (pc) @@ -3079,31 +3495,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 +3551,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; }") @@ -3367,18 +3776,13 @@ "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 (mem:BLK (match_operand:BLK 0 "address_operand" "")) + (mem:BLK (match_operand:BLK 1 "address_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 0)) + (clobber (match_dup 1))])] "" " { @@ -3386,22 +3790,20 @@ 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); }") +;; 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))] "" "* { @@ -3412,13 +3814,13 @@ if (INTVAL (operands[2]) & ~0x03) { xops[0] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) >> 2); - xops[1] = gen_rtx (REG, SImode, 2); + 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) @@ -3433,9 +3835,9 @@ (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" "")))) + (compare:CC + (mem:BLK (match_operand:BLK 1 "address_operand" "")) + (mem:BLK (match_operand:BLK 2 "address_operand" "")))) (use (match_operand:SI 3 "general_operand" "")) (use (match_operand:SI 4 "immediate_operand" "")) (clobber (match_dup 1)) @@ -3449,11 +3851,22 @@ operands[3] = copy_to_mode_reg (SImode, operands[3]); }") -(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")) +;; 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: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,9 +3874,13 @@ "" "* { - rtx xops[3]; + rtx xops[3], label; + label = gen_label_rtx (); + + output_asm_insn (AS2 (xor%B0,%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, @@ -3473,20 +3890,30 @@ output_asm_insn (AS2 (mov%B0,%1,%b0), xops); output_asm_insn (AS2 (sub%B0,%2,%b0), 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]; + + xops[0] = gen_rtx (REG, QImode, 0); + xops[1] = CONST0_RTX (QImode); + + output_asm_insn (AS2 (test%B0,%1,%0), xops); + return \"repz\;cmps%B2\"; +}") (define_expand "ffssi2" [(set (match_dup 2) @@ -3609,6 +4036,46 @@ "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 (AS2 (mov%L0,%1,%0), xops); + return \"repnz\;scas%B2\"; +}") + ;;- Local variables: ;;- mode:emacs-lisp ;;- comment-start: ";;- "