X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fconfig%2Fi386%2Fi386.md;h=6616da2e729eac2e8bb43fb55abf01577a22358b;hb=7959b7e646b493f48a2ea7228fbf1c43f84bedea;hp=22ea39cf79bf9f5bb21f1e2372de5a2098eaecec;hpb=7701acd11806a380ff36518b22d44969edbb01c1;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 22ea39cf79b..6616da2e729 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -1,6 +1,6 @@ ;; GCC machine description for IA-32 and x86-64. ;; Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -;; 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +;; 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 ;; Free Software Foundation, Inc. ;; Mostly by William Schelter. ;; x86_64 support added by Jan Hubicka @@ -30,7 +30,6 @@ ;; L,W,B,Q,S,T -- print the opcode suffix for specified size of operand. ;; C -- print opcode suffix for set/cmov insn. ;; c -- like C, but print reversed condition -;; E,e -- likewise, but for compare-and-branch fused insn. ;; F,f -- likewise, but for floating-point. ;; O -- if HAVE_AS_IX86_CMOV_SUN_SYNTAX, expand to "w.", "l." or "q.", ;; otherwise nothing @@ -57,191 +56,211 @@ ;; X -- don't print any sort of PIC '@' suffix for a symbol. ;; & -- print some in-use local-dynamic symbol name. ;; H -- print a memory address offset by 8; used for sse high-parts +;; Y -- print condition for XOP pcom* instruction. ;; + -- print a branch hint as 'cs' or 'ds' prefix ;; ; -- print a semicolon (after prefixes due to bug in older gas). ;; UNSPEC usage: -(define_constants - [; Relocation specifiers - (UNSPEC_GOT 0) - (UNSPEC_GOTOFF 1) - (UNSPEC_GOTPCREL 2) - (UNSPEC_GOTTPOFF 3) - (UNSPEC_TPOFF 4) - (UNSPEC_NTPOFF 5) - (UNSPEC_DTPOFF 6) - (UNSPEC_GOTNTPOFF 7) - (UNSPEC_INDNTPOFF 8) - (UNSPEC_PLTOFF 9) - (UNSPEC_MACHOPIC_OFFSET 10) - - ; Prologue support - (UNSPEC_STACK_ALLOC 11) - (UNSPEC_SET_GOT 12) - (UNSPEC_SSE_PROLOGUE_SAVE 13) - (UNSPEC_REG_SAVE 14) - (UNSPEC_DEF_CFA 15) - (UNSPEC_SET_RIP 16) - (UNSPEC_SET_GOT_OFFSET 17) - (UNSPEC_MEMORY_BLOCKAGE 18) - - ; TLS support - (UNSPEC_TP 20) - (UNSPEC_TLS_GD 21) - (UNSPEC_TLS_LD_BASE 22) - (UNSPEC_TLSDESC 23) - - ; Other random patterns - (UNSPEC_SCAS 30) - (UNSPEC_FNSTSW 31) - (UNSPEC_SAHF 32) - (UNSPEC_FSTCW 33) - (UNSPEC_ADD_CARRY 34) - (UNSPEC_FLDCW 35) - (UNSPEC_REP 36) - (UNSPEC_LD_MPIC 38) ; load_macho_picbase - (UNSPEC_TRUNC_NOOP 39) - - ; For SSE/MMX support: - (UNSPEC_FIX_NOTRUNC 40) - (UNSPEC_MASKMOV 41) - (UNSPEC_MOVMSK 42) - (UNSPEC_MOVNT 43) - (UNSPEC_MOVU 44) - (UNSPEC_RCP 45) - (UNSPEC_RSQRT 46) - (UNSPEC_SFENCE 47) - (UNSPEC_PFRCP 49) - (UNSPEC_PFRCPIT1 40) - (UNSPEC_PFRCPIT2 41) - (UNSPEC_PFRSQRT 42) - (UNSPEC_PFRSQIT1 43) - (UNSPEC_MFENCE 44) - (UNSPEC_LFENCE 45) - (UNSPEC_PSADBW 46) - (UNSPEC_LDDQU 47) - (UNSPEC_MS_TO_SYSV_CALL 48) - - ; Generic math support - (UNSPEC_COPYSIGN 50) - (UNSPEC_IEEE_MIN 51) ; not commutative - (UNSPEC_IEEE_MAX 52) ; not commutative - - ; x87 Floating point - (UNSPEC_SIN 60) - (UNSPEC_COS 61) - (UNSPEC_FPATAN 62) - (UNSPEC_FYL2X 63) - (UNSPEC_FYL2XP1 64) - (UNSPEC_FRNDINT 65) - (UNSPEC_FIST 66) - (UNSPEC_F2XM1 67) - (UNSPEC_TAN 68) - (UNSPEC_FXAM 69) - - ; x87 Rounding - (UNSPEC_FRNDINT_FLOOR 70) - (UNSPEC_FRNDINT_CEIL 71) - (UNSPEC_FRNDINT_TRUNC 72) - (UNSPEC_FRNDINT_MASK_PM 73) - (UNSPEC_FIST_FLOOR 74) - (UNSPEC_FIST_CEIL 75) - - ; x87 Double output FP - (UNSPEC_SINCOS_COS 80) - (UNSPEC_SINCOS_SIN 81) - (UNSPEC_XTRACT_FRACT 84) - (UNSPEC_XTRACT_EXP 85) - (UNSPEC_FSCALE_FRACT 86) - (UNSPEC_FSCALE_EXP 87) - (UNSPEC_FPREM_F 88) - (UNSPEC_FPREM_U 89) - (UNSPEC_FPREM1_F 90) - (UNSPEC_FPREM1_U 91) - - (UNSPEC_C2_FLAG 95) - (UNSPEC_FXAM_MEM 96) - - ; SSP patterns - (UNSPEC_SP_SET 100) - (UNSPEC_SP_TEST 101) - (UNSPEC_SP_TLS_SET 102) - (UNSPEC_SP_TLS_TEST 103) - - ; SSSE3 - (UNSPEC_PSHUFB 120) - (UNSPEC_PSIGN 121) - (UNSPEC_PALIGNR 122) - - ; For SSE4A support - (UNSPEC_EXTRQI 130) - (UNSPEC_EXTRQ 131) - (UNSPEC_INSERTQI 132) - (UNSPEC_INSERTQ 133) - - ; For SSE4.1 support - (UNSPEC_BLENDV 134) - (UNSPEC_INSERTPS 135) - (UNSPEC_DP 136) - (UNSPEC_MOVNTDQA 137) - (UNSPEC_MPSADBW 138) - (UNSPEC_PHMINPOSUW 139) - (UNSPEC_PTEST 140) - (UNSPEC_ROUND 141) - - ; For SSE4.2 support - (UNSPEC_CRC32 143) - (UNSPEC_PCMPESTR 144) - (UNSPEC_PCMPISTR 145) - - ; For FMA4 support - (UNSPEC_FMA4_INTRINSIC 150) - (UNSPEC_FMA4_FMADDSUB 151) - (UNSPEC_FMA4_FMSUBADD 152) - ; For AES support - (UNSPEC_AESENC 159) - (UNSPEC_AESENCLAST 160) - (UNSPEC_AESDEC 161) - (UNSPEC_AESDECLAST 162) - (UNSPEC_AESIMC 163) - (UNSPEC_AESKEYGENASSIST 164) - - ; For PCLMUL support - (UNSPEC_PCLMUL 165) - - ; For AVX support - (UNSPEC_PCMP 166) - (UNSPEC_VPERMIL 167) - (UNSPEC_VPERMIL2F128 168) - (UNSPEC_MASKLOAD 169) - (UNSPEC_MASKSTORE 170) - (UNSPEC_CAST 171) - (UNSPEC_VTESTP 172) - ]) - -(define_constants - [(UNSPECV_BLOCKAGE 0) - (UNSPECV_STACK_PROBE 1) - (UNSPECV_EMMS 2) - (UNSPECV_LDMXCSR 3) - (UNSPECV_STMXCSR 4) - (UNSPECV_FEMMS 5) - (UNSPECV_CLFLUSH 6) - (UNSPECV_ALIGN 7) - (UNSPECV_MONITOR 8) - (UNSPECV_MWAIT 9) - (UNSPECV_CMPXCHG 10) - (UNSPECV_XCHG 12) - (UNSPECV_LOCK 13) - (UNSPECV_PROLOGUE_USE 14) - (UNSPECV_CLD 15) - (UNSPECV_VZEROALL 16) - (UNSPECV_VZEROUPPER 17) - (UNSPECV_RDTSC 18) - (UNSPECV_RDTSCP 19) - (UNSPECV_RDPMC 20) - ]) +(define_c_enum "unspec" [ + ;; Relocation specifiers + UNSPEC_GOT + UNSPEC_GOTOFF + UNSPEC_GOTPCREL + UNSPEC_GOTTPOFF + UNSPEC_TPOFF + UNSPEC_NTPOFF + UNSPEC_DTPOFF + UNSPEC_GOTNTPOFF + UNSPEC_INDNTPOFF + UNSPEC_PLTOFF + UNSPEC_MACHOPIC_OFFSET + + ;; Prologue support + UNSPEC_STACK_ALLOC + UNSPEC_SET_GOT + UNSPEC_REG_SAVE + UNSPEC_DEF_CFA + UNSPEC_SET_RIP + UNSPEC_SET_GOT_OFFSET + UNSPEC_MEMORY_BLOCKAGE + + ;; TLS support + UNSPEC_TP + UNSPEC_TLS_GD + UNSPEC_TLS_LD_BASE + UNSPEC_TLSDESC + + ;; Other random patterns + UNSPEC_SCAS + UNSPEC_FNSTSW + UNSPEC_SAHF + UNSPEC_PARITY + UNSPEC_FSTCW + UNSPEC_ADD_CARRY + UNSPEC_FLDCW + UNSPEC_REP + UNSPEC_LD_MPIC ; load_macho_picbase + UNSPEC_TRUNC_NOOP + + ;; For SSE/MMX support: + UNSPEC_FIX_NOTRUNC + UNSPEC_MASKMOV + UNSPEC_MOVMSK + UNSPEC_MOVNT + UNSPEC_MOVU + UNSPEC_RCP + UNSPEC_RSQRT + UNSPEC_SFENCE + UNSPEC_PFRCP + UNSPEC_PFRCPIT1 + UNSPEC_PFRCPIT2 + UNSPEC_PFRSQRT + UNSPEC_PFRSQIT1 + UNSPEC_MFENCE + UNSPEC_LFENCE + UNSPEC_PSADBW + UNSPEC_LDDQU + UNSPEC_MS_TO_SYSV_CALL + + ;; Generic math support + UNSPEC_COPYSIGN + UNSPEC_IEEE_MIN ; not commutative + UNSPEC_IEEE_MAX ; not commutative + + ;; x87 Floating point + UNSPEC_SIN + UNSPEC_COS + UNSPEC_FPATAN + UNSPEC_FYL2X + UNSPEC_FYL2XP1 + UNSPEC_FRNDINT + UNSPEC_FIST + UNSPEC_F2XM1 + UNSPEC_TAN + UNSPEC_FXAM + + ;; x87 Rounding + UNSPEC_FRNDINT_FLOOR + UNSPEC_FRNDINT_CEIL + UNSPEC_FRNDINT_TRUNC + UNSPEC_FRNDINT_MASK_PM + UNSPEC_FIST_FLOOR + UNSPEC_FIST_CEIL + + ;; x87 Double output FP + UNSPEC_SINCOS_COS + UNSPEC_SINCOS_SIN + UNSPEC_XTRACT_FRACT + UNSPEC_XTRACT_EXP + UNSPEC_FSCALE_FRACT + UNSPEC_FSCALE_EXP + UNSPEC_FPREM_F + UNSPEC_FPREM_U + UNSPEC_FPREM1_F + UNSPEC_FPREM1_U + + UNSPEC_C2_FLAG + UNSPEC_FXAM_MEM + + ;; SSP patterns + UNSPEC_SP_SET + UNSPEC_SP_TEST + UNSPEC_SP_TLS_SET + UNSPEC_SP_TLS_TEST + + ;; SSSE3 + UNSPEC_PSHUFB + UNSPEC_PSIGN + UNSPEC_PALIGNR + + ;; For SSE4A support + UNSPEC_EXTRQI + UNSPEC_EXTRQ + UNSPEC_INSERTQI + UNSPEC_INSERTQ + + ;; For SSE4.1 support + UNSPEC_BLENDV + UNSPEC_INSERTPS + UNSPEC_DP + UNSPEC_MOVNTDQA + UNSPEC_MPSADBW + UNSPEC_PHMINPOSUW + UNSPEC_PTEST + UNSPEC_ROUND + + ;; For SSE4.2 support + UNSPEC_CRC32 + UNSPEC_PCMPESTR + UNSPEC_PCMPISTR + + ;; For FMA4 support + UNSPEC_FMA4_INTRINSIC + UNSPEC_FMA4_FMADDSUB + UNSPEC_FMA4_FMSUBADD + UNSPEC_XOP_UNSIGNED_CMP + UNSPEC_XOP_TRUEFALSE + UNSPEC_XOP_PERMUTE + UNSPEC_FRCZ + + ;; For AES support + UNSPEC_AESENC + UNSPEC_AESENCLAST + UNSPEC_AESDEC + UNSPEC_AESDECLAST + UNSPEC_AESIMC + UNSPEC_AESKEYGENASSIST + + ;; For PCLMUL support + UNSPEC_PCLMUL + + ;; For AVX support + UNSPEC_PCMP + UNSPEC_VPERMIL + UNSPEC_VPERMIL2 + UNSPEC_VPERMIL2F128 + UNSPEC_MASKLOAD + UNSPEC_MASKSTORE + UNSPEC_CAST + UNSPEC_VTESTP + UNSPEC_VCVTPH2PS + UNSPEC_VCVTPS2PH +]) + +(define_c_enum "unspecv" [ + UNSPECV_BLOCKAGE + UNSPECV_STACK_PROBE + UNSPECV_PROBE_STACK_RANGE + UNSPECV_EMMS + UNSPECV_LDMXCSR + UNSPECV_STMXCSR + UNSPECV_FEMMS + UNSPECV_CLFLUSH + UNSPECV_ALIGN + UNSPECV_MONITOR + UNSPECV_MWAIT + UNSPECV_CMPXCHG + UNSPECV_XCHG + UNSPECV_LOCK + UNSPECV_PROLOGUE_USE + UNSPECV_CLD + UNSPECV_VZEROALL + UNSPECV_VZEROUPPER + UNSPECV_RDTSC + UNSPECV_RDTSCP + UNSPECV_RDPMC + UNSPECV_VSWAPMOV + UNSPECV_LLWP_INTRINSIC + UNSPECV_SLWP_INTRINSIC + UNSPECV_LWPVAL_INTRINSIC + UNSPECV_LWPINS_INTRINSIC + UNSPECV_RDFSBASE + UNSPECV_RDGSBASE + UNSPECV_WRFSBASE + UNSPECV_WRGSBASE + UNSPECV_RDRAND +]) ;; Constants to represent pcomtrue/pcomfalse variants (define_constants @@ -253,6 +272,20 @@ (COM_TRUE_P 5) ]) +;; Constants used in the XOP pperm instruction +(define_constants + [(PPERM_SRC 0x00) /* copy source */ + (PPERM_INVERT 0x20) /* invert source */ + (PPERM_REVERSE 0x40) /* bit reverse source */ + (PPERM_REV_INV 0x60) /* bit reverse & invert src */ + (PPERM_ZERO 0x80) /* all 0's */ + (PPERM_ONES 0xa0) /* all 1's */ + (PPERM_SIGN 0xc0) /* propagate sign bit */ + (PPERM_INV_SIGN 0xe0) /* invert & propagate sign */ + (PPERM_SRC1 0x00) /* use first source byte */ + (PPERM_SRC2 0x10) /* use second source byte */ + ]) + ;; Registers by name. (define_constants [(AX_REG 0) @@ -317,7 +350,7 @@ ;; Processor type. (define_attr "cpu" "none,pentium,pentiumpro,geode,k6,athlon,k8,core2,atom, - generic64,amdfam10" + generic64,amdfam10,bdver1" (const (symbol_ref "ix86_schedule"))) ;; A basic instruction type. Refinements due to arguments to be @@ -330,9 +363,9 @@ push,pop,call,callv,leave, str,bitmanip, fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp,fisttp,frndint, - sselog,sselog1,sseiadd,sseiadd1,sseishft,sseimul, + sselog,sselog1,sseiadd,sseiadd1,sseishft,sseishft1,sseimul, sse,ssemov,sseadd,ssemul,ssecmp,ssecomi,ssecvt,ssecvt1,sseicvt,ssediv,sseins, - ssemuladd,sse4arg, + ssemuladd,sse4arg,lwp, mmx,mmxmov,mmxadd,mmxmul,mmxcmp,mmxcvt,mmxshft" (const_string "other")) @@ -345,7 +378,7 @@ (define_attr "unit" "integer,i387,sse,mmx,unknown" (cond [(eq_attr "type" "fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp,fisttp,frndint") (const_string "i387") - (eq_attr "type" "sselog,sselog1,sseiadd,sseiadd1,sseishft,sseimul, + (eq_attr "type" "sselog,sselog1,sseiadd,sseiadd1,sseishft,sseishft1,sseimul, sse,ssemov,sseadd,ssemul,ssecmp,ssecomi,ssecvt, ssecvt1,sseicvt,ssediv,sseins,ssemuladd,sse4arg") (const_string "sse") @@ -553,7 +586,7 @@ ;; if the instruction is complex. (define_attr "memory" "none,load,store,both,unknown" - (cond [(eq_attr "type" "other,multi,str") + (cond [(eq_attr "type" "other,multi,str,lwp") (const_string "unknown") (eq_attr "type" "lea,fcmov,fpspc") (const_string "none") @@ -652,11 +685,11 @@ (set_attr "type" "multi")]) ;; All integer comparison codes. -(define_code_iterator int_cond [ne eq ge gt le lt geu gtu leu ltu ]) +(define_code_iterator int_cond [ne eq ge gt le lt geu gtu leu ltu]) ;; All floating-point comparison codes. (define_code_iterator fp_cond [unordered ordered - uneq unge ungt unle unlt ltgt ]) + uneq unge ungt unle unlt ltgt]) (define_code_iterator plusminus [plus minus]) @@ -671,6 +704,8 @@ (define_code_attr plusminus_mnemonic [(plus "add") (ss_plus "adds") (us_plus "addus") (minus "sub") (ss_minus "subs") (us_minus "subus")]) +(define_code_attr plusminus_carry_mnemonic + [(plus "adc") (minus "sbb")]) ;; Mark commutative operators as such in constraints. (define_code_attr comm [(plus "%") (ss_plus "%") (us_plus "%") @@ -686,40 +721,74 @@ (define_code_iterator maxmin [smax smin umax umin]) ;; Base name for integer and FP insn mnemonic -(define_code_attr maxminiprefix [(smax "maxs") (smin "mins") - (umax "maxu") (umin "minu")]) -(define_code_attr maxminfprefix [(smax "max") (smin "min")]) +(define_code_attr maxmin_int [(smax "maxs") (smin "mins") + (umax "maxu") (umin "minu")]) +(define_code_attr maxmin_float [(smax "max") (smin "min")]) + +;; Mapping of logic operators +(define_code_iterator any_logic [and ior xor]) +(define_code_iterator any_or [ior xor]) + +;; Base name for insn mnemonic. +(define_code_attr logic [(and "and") (ior "or") (xor "xor")]) + +;; Mapping of shift-right operators +(define_code_iterator any_shiftrt [lshiftrt ashiftrt]) + +;; Base name for define_insn +(define_code_attr shiftrt_insn [(lshiftrt "lshr") (ashiftrt "ashr")]) + +;; Base name for insn mnemonic. +(define_code_attr shiftrt [(lshiftrt "shr") (ashiftrt "sar")]) + +;; Mapping of rotate operators +(define_code_iterator any_rotate [rotate rotatert]) -;; Mapping of parallel logic operators -(define_code_iterator plogic [and ior xor]) +;; Base name for define_insn +(define_code_attr rotate_insn [(rotate "rotl") (rotatert "rotr")]) ;; Base name for insn mnemonic. -(define_code_attr plogicprefix [(and "and") (ior "or") (xor "xor")]) +(define_code_attr rotate [(rotate "rol") (rotatert "ror")]) ;; Mapping of abs neg operators (define_code_iterator absneg [abs neg]) ;; Base name for x87 insn mnemonic. -(define_code_attr absnegprefix [(abs "abs") (neg "chs")]) +(define_code_attr absneg_mnemonic [(abs "abs") (neg "chs")]) ;; Used in signed and unsigned widening multiplications. (define_code_iterator any_extend [sign_extend zero_extend]) -;; Used in signed and unsigned divisions. -(define_code_iterator any_div [div udiv]) - ;; Various insn prefixes for signed and unsigned operations. (define_code_attr u [(sign_extend "") (zero_extend "u") (div "") (udiv "u")]) (define_code_attr s [(sign_extend "s") (zero_extend "u")]) +;; Used in signed and unsigned divisions. +(define_code_iterator any_div [div udiv]) + ;; Instruction prefix for signed and unsigned operations. (define_code_attr sgnprefix [(sign_extend "i") (zero_extend "") (div "i") (udiv "")]) -;; All single word integer modes. +;; 64bit single word integer modes. +(define_mode_iterator SWI1248x [QI HI SI DI]) + +;; 64bit single word integer modes without QImode and HImode. +(define_mode_iterator SWI48x [SI DI]) + +;; Single word integer modes. (define_mode_iterator SWI [QI HI SI (DI "TARGET_64BIT")]) +;; Single word integer modes without SImode and DImode. +(define_mode_iterator SWI12 [QI HI]) + +;; Single word integer modes without DImode. +(define_mode_iterator SWI124 [QI HI SI]) + +;; Single word integer modes without QImode and DImode. +(define_mode_iterator SWI24 [HI SI]) + ;; Single word integer modes without QImode. (define_mode_iterator SWI248 [HI SI (DI "TARGET_64BIT")]) @@ -736,18 +805,27 @@ (HI "TARGET_HIMODE_MATH") SI (DI "TARGET_64BIT")]) +;; Math-dependant single word integer modes without DImode. +(define_mode_iterator SWIM124 [(QI "TARGET_QIMODE_MATH") + (HI "TARGET_HIMODE_MATH") + SI]) + ;; Math-dependant single word integer modes without QImode. (define_mode_iterator SWIM248 [(HI "TARGET_HIMODE_MATH") SI (DI "TARGET_64BIT")]) -;; Half mode for double word integer modes. -(define_mode_iterator DWIH [(SI "!TARGET_64BIT") - (DI "TARGET_64BIT")]) - ;; Double word integer modes. +(define_mode_iterator DWI [(DI "!TARGET_64BIT") + (TI "TARGET_64BIT")]) + +;; Double word integer modes as mode attribute. (define_mode_attr DWI [(SI "DI") (DI "TI")]) (define_mode_attr dwi [(SI "di") (DI "ti")]) +;; Half mode for double word integer modes. +(define_mode_iterator DWIH [(SI "!TARGET_64BIT") + (DI "TARGET_64BIT")]) + ;; Instruction suffix for integer modes. (define_mode_attr imodesuffix [(QI "b") (HI "w") (SI "l") (DI "q")]) @@ -758,11 +836,14 @@ (define_mode_attr i [(QI "n") (HI "n") (SI "i") (DI "e")]) ;; General operand constraint for word modes. -(define_mode_attr g [(SI "g") (DI "rme")]) +(define_mode_attr g [(QI "qmn") (HI "rmn") (SI "g") (DI "rme")]) ;; Immediate operand constraint for double integer modes. (define_mode_attr di [(SI "iF") (DI "e")]) +;; Immediate operand constraint for shifts. +(define_mode_attr S [(QI "I") (HI "I") (SI "I") (DI "J") (TI "O")]) + ;; General operand predicate for integer modes. (define_mode_attr general_operand [(QI "general_operand") @@ -771,6 +852,43 @@ (DI "x86_64_general_operand") (TI "x86_64_general_operand")]) +;; General sign/zero extend operand predicate for integer modes. +(define_mode_attr general_szext_operand + [(QI "general_operand") + (HI "general_operand") + (SI "general_operand") + (DI "x86_64_szext_general_operand")]) + +;; Immediate operand predicate for integer modes. +(define_mode_attr immediate_operand + [(QI "immediate_operand") + (HI "immediate_operand") + (SI "immediate_operand") + (DI "x86_64_immediate_operand")]) + +;; Operand predicate for shifts. +(define_mode_attr shift_operand + [(QI "nonimmediate_operand") + (HI "nonimmediate_operand") + (SI "nonimmediate_operand") + (DI "shiftdi_operand") + (TI "register_operand")]) + +;; Operand predicate for shift argument. +(define_mode_attr shift_immediate_operand + [(QI "const_1_to_31_operand") + (HI "const_1_to_31_operand") + (SI "const_1_to_31_operand") + (DI "const_1_to_63_operand")]) + +;; Input operand predicate for arithmetic left shifts. +(define_mode_attr ashl_input_operand + [(QI "nonimmediate_operand") + (HI "nonimmediate_operand") + (SI "nonimmediate_operand") + (DI "ashldi_input_operand") + (TI "reg_or_pm1_operand")]) + ;; SSE and x87 SFmode and DFmode floating point modes (define_mode_iterator MODEF [SF DF]) @@ -818,322 +936,80 @@ ;; Compare and branch/compare and store instructions. -(define_expand "cbranchti4" - [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:TI 1 "nonimmediate_operand" "") - (match_operand:TI 2 "x86_64_general_operand" ""))) - (set (pc) (if_then_else - (match_operator 0 "comparison_operator" - [(reg:CC FLAGS_REG) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "TARGET_64BIT" -{ - if (MEM_P (operands[1]) && MEM_P (operands[2])) - operands[1] = force_reg (TImode, operands[1]); - ix86_compare_op0 = operands[1]; - ix86_compare_op1 = operands[2]; - ix86_expand_branch (GET_CODE (operands[0]), operands[3]); - DONE; -}) - -(define_expand "cbranchdi4" - [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:DI 2 "x86_64_general_operand" ""))) - (set (pc) (if_then_else - (match_operator 0 "comparison_operator" - [(reg:CC FLAGS_REG) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "" -{ - if (MEM_P (operands[1]) && MEM_P (operands[2])) - operands[1] = force_reg (DImode, operands[1]); - ix86_compare_op0 = operands[1]; - ix86_compare_op1 = operands[2]; - ix86_expand_branch (GET_CODE (operands[0]), operands[3]); - DONE; -}) - -(define_expand "cstoredi4" - [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:DI 2 "nonimmediate_operand" "") - (match_operand:DI 3 "x86_64_general_operand" ""))) - (set (match_operand:QI 0 "register_operand" "") - (match_operator 1 "comparison_operator" - [(reg:CC FLAGS_REG) - (const_int 0)]))] - "TARGET_64BIT" -{ - if (MEM_P (operands[2]) && MEM_P (operands[3])) - operands[2] = force_reg (DImode, operands[2]); - ix86_compare_op0 = operands[2]; - ix86_compare_op1 = operands[3]; - ix86_expand_setcc (GET_CODE (operands[1]), operands[0]); - DONE; -}) - -(define_expand "cbranchsi4" - [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:SI 1 "cmpsi_operand" "") - (match_operand:SI 2 "general_operand" ""))) - (set (pc) (if_then_else - (match_operator 0 "comparison_operator" - [(reg:CC FLAGS_REG) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "" -{ - if (MEM_P (operands[1]) && MEM_P (operands[2])) - operands[1] = force_reg (SImode, operands[1]); - ix86_compare_op0 = operands[1]; - ix86_compare_op1 = operands[2]; - ix86_expand_branch (GET_CODE (operands[0]), operands[3]); - DONE; -}) - -(define_expand "cstoresi4" - [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:SI 2 "cmpsi_operand" "") - (match_operand:SI 3 "general_operand" ""))) - (set (match_operand:QI 0 "register_operand" "") - (match_operator 1 "comparison_operator" - [(reg:CC FLAGS_REG) - (const_int 0)]))] - "" -{ - if (MEM_P (operands[2]) && MEM_P (operands[3])) - operands[2] = force_reg (SImode, operands[2]); - ix86_compare_op0 = operands[2]; - ix86_compare_op1 = operands[3]; - ix86_expand_setcc (GET_CODE (operands[1]), operands[0]); - DONE; -}) - -(define_expand "cbranchhi4" - [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:HI 2 "general_operand" ""))) - (set (pc) (if_then_else - (match_operator 0 "comparison_operator" - [(reg:CC FLAGS_REG) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "" -{ - if (MEM_P (operands[1]) && MEM_P (operands[2])) - operands[1] = force_reg (HImode, operands[1]); - ix86_compare_op0 = operands[1]; - ix86_compare_op1 = operands[2]; - ix86_expand_branch (GET_CODE (operands[0]), operands[3]); - DONE; -}) - -(define_expand "cstorehi4" - [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:HI 2 "nonimmediate_operand" "") - (match_operand:HI 3 "general_operand" ""))) - (set (match_operand:QI 0 "register_operand" "") - (match_operator 1 "comparison_operator" - [(reg:CC FLAGS_REG) - (const_int 0)]))] - "" -{ - if (MEM_P (operands[2]) && MEM_P (operands[3])) - operands[2] = force_reg (HImode, operands[2]); - ix86_compare_op0 = operands[2]; - ix86_compare_op1 = operands[3]; - ix86_expand_setcc (GET_CODE (operands[1]), operands[0]); - DONE; -}) - - -(define_expand "cbranchqi4" +(define_expand "cbranch4" [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "general_operand" ""))) + (compare:CC (match_operand:SDWIM 1 "nonimmediate_operand" "") + (match_operand:SDWIM 2 "" ""))) (set (pc) (if_then_else - (match_operator 0 "comparison_operator" - [(reg:CC FLAGS_REG) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] + (match_operator 0 "comparison_operator" + [(reg:CC FLAGS_REG) (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc)))] "" { if (MEM_P (operands[1]) && MEM_P (operands[2])) - operands[1] = force_reg (QImode, operands[1]); + operands[1] = force_reg (mode, operands[1]); ix86_compare_op0 = operands[1]; ix86_compare_op1 = operands[2]; ix86_expand_branch (GET_CODE (operands[0]), operands[3]); DONE; }) - -(define_expand "cstoreqi4" +(define_expand "cstore4" [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:QI 2 "nonimmediate_operand" "") - (match_operand:QI 3 "general_operand" ""))) + (compare:CC (match_operand:SWIM 2 "nonimmediate_operand" "") + (match_operand:SWIM 3 "" ""))) (set (match_operand:QI 0 "register_operand" "") - (match_operator 1 "comparison_operator" - [(reg:CC FLAGS_REG) - (const_int 0)]))] + (match_operator 1 "comparison_operator" + [(reg:CC FLAGS_REG) (const_int 0)]))] "" { if (MEM_P (operands[2]) && MEM_P (operands[3])) - operands[2] = force_reg (QImode, operands[2]); + operands[2] = force_reg (mode, operands[2]); ix86_compare_op0 = operands[2]; ix86_compare_op1 = operands[3]; ix86_expand_setcc (GET_CODE (operands[1]), operands[0]); DONE; }) - -(define_insn "cmpdi_ccno_1_rex64" - [(set (reg FLAGS_REG) - (compare (match_operand:DI 0 "nonimmediate_operand" "r,?mr") - (match_operand:DI 1 "const0_operand" "")))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" - "@ - test{q}\t%0, %0 - cmp{q}\t{%1, %0|%0, %1}" - [(set_attr "type" "test,icmp") - (set_attr "length_immediate" "0,1") - (set_attr "mode" "DI")]) - -(define_insn "*cmpdi_minus_1_rex64" - [(set (reg FLAGS_REG) - (compare (minus:DI (match_operand:DI 0 "nonimmediate_operand" "rm,r") - (match_operand:DI 1 "x86_64_general_operand" "re,mr")) - (const_int 0)))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)" - "cmp{q}\t{%1, %0|%0, %1}" - [(set_attr "type" "icmp") - (set_attr "mode" "DI")]) - -(define_expand "cmpdi_1_rex64" - [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:DI 0 "nonimmediate_operand" "") - (match_operand:DI 1 "general_operand" "")))] - "TARGET_64BIT" - "") - -(define_insn "cmpdi_1_insn_rex64" - [(set (reg FLAGS_REG) - (compare (match_operand:DI 0 "nonimmediate_operand" "mr,r") - (match_operand:DI 1 "x86_64_general_operand" "re,mr")))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCmode)" - "cmp{q}\t{%1, %0|%0, %1}" - [(set_attr "type" "icmp") - (set_attr "mode" "DI")]) - - -(define_insn "*cmpsi_ccno_1" - [(set (reg FLAGS_REG) - (compare (match_operand:SI 0 "nonimmediate_operand" "r,?mr") - (match_operand:SI 1 "const0_operand" "")))] - "ix86_match_ccmode (insn, CCNOmode)" - "@ - test{l}\t%0, %0 - cmp{l}\t{%1, %0|%0, %1}" - [(set_attr "type" "test,icmp") - (set_attr "length_immediate" "0,1") - (set_attr "mode" "SI")]) - -(define_insn "*cmpsi_minus_1" - [(set (reg FLAGS_REG) - (compare (minus:SI (match_operand:SI 0 "nonimmediate_operand" "rm,r") - (match_operand:SI 1 "general_operand" "ri,mr")) - (const_int 0)))] - "ix86_match_ccmode (insn, CCGOCmode)" - "cmp{l}\t{%1, %0|%0, %1}" - [(set_attr "type" "icmp") - (set_attr "mode" "SI")]) - -(define_expand "cmpsi_1" +(define_expand "cmp_1" [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:SI 0 "nonimmediate_operand" "") - (match_operand:SI 1 "general_operand" "")))] + (compare:CC (match_operand:SWI48 0 "nonimmediate_operand" "") + (match_operand:SWI48 1 "" "")))] "" "") -(define_insn "*cmpsi_1_insn" - [(set (reg FLAGS_REG) - (compare (match_operand:SI 0 "nonimmediate_operand" "rm,r") - (match_operand:SI 1 "general_operand" "ri,mr")))] - "!(MEM_P (operands[0]) && MEM_P (operands[1])) - && ix86_match_ccmode (insn, CCmode)" - "cmp{l}\t{%1, %0|%0, %1}" - [(set_attr "type" "icmp") - (set_attr "mode" "SI")]) - -(define_insn "*cmphi_ccno_1" - [(set (reg FLAGS_REG) - (compare (match_operand:HI 0 "nonimmediate_operand" "r,?mr") - (match_operand:HI 1 "const0_operand" "")))] - "ix86_match_ccmode (insn, CCNOmode)" - "@ - test{w}\t%0, %0 - cmp{w}\t{%1, %0|%0, %1}" - [(set_attr "type" "test,icmp") - (set_attr "length_immediate" "0,1") - (set_attr "mode" "HI")]) - -(define_insn "*cmphi_minus_1" - [(set (reg FLAGS_REG) - (compare (minus:HI (match_operand:HI 0 "nonimmediate_operand" "rm,r") - (match_operand:HI 1 "general_operand" "rn,mr")) - (const_int 0)))] - "ix86_match_ccmode (insn, CCGOCmode)" - "cmp{w}\t{%1, %0|%0, %1}" - [(set_attr "type" "icmp") - (set_attr "mode" "HI")]) - -(define_insn "*cmphi_1" - [(set (reg FLAGS_REG) - (compare (match_operand:HI 0 "nonimmediate_operand" "rm,r") - (match_operand:HI 1 "general_operand" "rn,mr")))] - "!(MEM_P (operands[0]) && MEM_P (operands[1])) - && ix86_match_ccmode (insn, CCmode)" - "cmp{w}\t{%1, %0|%0, %1}" - [(set_attr "type" "icmp") - (set_attr "mode" "HI")]) - -(define_insn "*cmpqi_ccno_1" +(define_insn "*cmp_ccno_1" [(set (reg FLAGS_REG) - (compare (match_operand:QI 0 "nonimmediate_operand" "q,?mq") - (match_operand:QI 1 "const0_operand" "")))] + (compare (match_operand:SWI 0 "nonimmediate_operand" ",?m") + (match_operand:SWI 1 "const0_operand" "")))] "ix86_match_ccmode (insn, CCNOmode)" "@ - test{b}\t%0, %0 - cmp{b}\t{$0, %0|%0, 0}" + test{}\t%0, %0 + cmp{}\t{%1, %0|%0, %1}" [(set_attr "type" "test,icmp") (set_attr "length_immediate" "0,1") - (set_attr "mode" "QI")]) + (set_attr "mode" "")]) -(define_insn "*cmpqi_1" +(define_insn "*cmp_1" [(set (reg FLAGS_REG) - (compare (match_operand:QI 0 "nonimmediate_operand" "qm,q") - (match_operand:QI 1 "general_operand" "qn,mq")))] - "!(MEM_P (operands[0]) && MEM_P (operands[1])) - && ix86_match_ccmode (insn, CCmode)" - "cmp{b}\t{%1, %0|%0, %1}" + (compare (match_operand:SWI 0 "nonimmediate_operand" "m,") + (match_operand:SWI 1 "" ",m")))] + "ix86_match_ccmode (insn, CCmode)" + "cmp{}\t{%1, %0|%0, %1}" [(set_attr "type" "icmp") - (set_attr "mode" "QI")]) + (set_attr "mode" "")]) -(define_insn "*cmpqi_minus_1" +(define_insn "*cmp_minus_1" [(set (reg FLAGS_REG) - (compare (minus:QI (match_operand:QI 0 "nonimmediate_operand" "qm,q") - (match_operand:QI 1 "general_operand" "qn,mq")) - (const_int 0)))] + (compare + (minus:SWI (match_operand:SWI 0 "nonimmediate_operand" "m,") + (match_operand:SWI 1 "" ",m")) + (const_int 0)))] "ix86_match_ccmode (insn, CCGOCmode)" - "cmp{b}\t{%1, %0|%0, %1}" + "cmp{}\t{%1, %0|%0, %1}" [(set_attr "type" "icmp") - (set_attr "mode" "QI")]) + (set_attr "mode" "")]) (define_insn "*cmpqi_ext_1" [(set (reg FLAGS_REG) @@ -1186,11 +1062,11 @@ (match_operand 0 "ext_register_operand" "") (const_int 8) (const_int 8)) 0) - (match_operand:QI 1 "general_operand" "")))] + (match_operand:QI 1 "immediate_operand" "")))] "" "") -(define_insn "cmpqi_ext_3_insn" +(define_insn "*cmpqi_ext_3_insn" [(set (reg FLAGS_REG) (compare (subreg:QI @@ -1205,7 +1081,7 @@ (set_attr "modrm" "1") (set_attr "mode" "QI")]) -(define_insn "cmpqi_ext_3_insn_rex64" +(define_insn "*cmpqi_ext_3_insn_rex64" [(set (reg FLAGS_REG) (compare (subreg:QI @@ -1578,11 +1454,12 @@ UNSPEC_SAHF))] "TARGET_SAHF" { -#ifdef HAVE_AS_IX86_SAHF - return "sahf"; -#else - return ASM_BYTE "0x9e"; +#ifndef HAVE_AS_IX86_SAHF + if (TARGET_64BIT) + return ASM_BYTE "0x9e"; + else #endif + return "sahf"; } [(set_attr "length" "1") (set_attr "athlon_decode" "vector") @@ -1733,24 +1610,131 @@ ;; Move instructions. -;; General case of fullword move. - -(define_expand "movsi" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (match_operand:SI 1 "general_operand" ""))] - "" - "ix86_expand_move (SImode, operands); DONE;") - -;; Push/pop instructions. They are separate since autoinc/dec is not a -;; general_operand. -;; -;; %%% We don't use a post-inc memory reference because x86 is not a -;; general AUTO_INC_DEC host, which impacts how it is treated in flow. -;; Changing this impacts compiler performance on other non-AUTO_INC_DEC -;; targets without our curiosities, and it is just as easy to represent -;; this differently. +(define_expand "movoi" + [(set (match_operand:OI 0 "nonimmediate_operand" "") + (match_operand:OI 1 "general_operand" ""))] + "TARGET_AVX" + "ix86_expand_move (OImode, operands); DONE;") -(define_insn "*pushsi2" +(define_expand "movti" + [(set (match_operand:TI 0 "nonimmediate_operand" "") + (match_operand:TI 1 "nonimmediate_operand" ""))] + "TARGET_64BIT || TARGET_SSE" +{ + if (TARGET_64BIT) + ix86_expand_move (TImode, operands); + else if (push_operand (operands[0], TImode)) + ix86_expand_push (TImode, operands[1]); + else + ix86_expand_vector_move (TImode, operands); + DONE; +}) + +;; This expands to what emit_move_complex would generate if we didn't +;; have a movti pattern. Having this avoids problems with reload on +;; 32-bit targets when SSE is present, but doesn't seem to be harmful +;; to have around all the time. +(define_expand "movcdi" + [(set (match_operand:CDI 0 "nonimmediate_operand" "") + (match_operand:CDI 1 "general_operand" ""))] + "" +{ + if (push_operand (operands[0], CDImode)) + emit_move_complex_push (CDImode, operands[0], operands[1]); + else + emit_move_complex_parts (operands[0], operands[1]); + DONE; +}) + +(define_expand "mov" + [(set (match_operand:SWI1248x 0 "nonimmediate_operand" "") + (match_operand:SWI1248x 1 "general_operand" ""))] + "" + "ix86_expand_move (mode, operands); DONE;") + +;; Push/pop instructions. They are separate since autoinc/dec is not a +;; general_operand. +;; +;; %%% We don't use a post-inc memory reference because x86 is not a +;; general AUTO_INC_DEC host, which impacts how it is treated in flow. +;; Changing this impacts compiler performance on other non-AUTO_INC_DEC +;; targets without our curiosities, and it is just as easy to represent +;; this differently. + +(define_insn "*pushdi2_rex64" + [(set (match_operand:DI 0 "push_operand" "=<,!<") + (match_operand:DI 1 "general_no_elim_operand" "re*m,n"))] + "TARGET_64BIT" + "@ + push{q}\t%1 + #" + [(set_attr "type" "push,multi") + (set_attr "mode" "DI")]) + +;; Convert impossible pushes of immediate to existing instructions. +;; First try to get scratch register and go through it. In case this +;; fails, push sign extended lower part first and then overwrite +;; upper part by 32bit move. +(define_peephole2 + [(match_scratch:DI 2 "r") + (set (match_operand:DI 0 "push_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode)" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") + +;; We need to define this as both peepholer and splitter for case +;; peephole2 pass is not run. +;; "&& 1" is needed to keep it from matching the previous pattern. +(define_peephole2 + [(set (match_operand:DI 0 "push_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode) && 1" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (match_dup 3))] +{ + split_di (&operands[1], 1, &operands[2], &operands[3]); + + operands[1] = gen_lowpart (DImode, operands[2]); + operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (DImode, stack_pointer_rtx, + GEN_INT (4))); +}) + +(define_split + [(set (match_operand:DI 0 "push_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && ((optimize > 0 && flag_peephole2) + ? epilogue_completed : reload_completed) + && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode)" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (match_dup 3))] +{ + split_di (&operands[1], 1, &operands[2], &operands[3]); + + operands[1] = gen_lowpart (DImode, operands[2]); + operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (DImode, stack_pointer_rtx, + GEN_INT (4))); +}) + +(define_insn "*pushdi2" + [(set (match_operand:DI 0 "push_operand" "=<") + (match_operand:DI 1 "general_no_elim_operand" "riF*m"))] + "!TARGET_64BIT" + "#") + +(define_split + [(set (match_operand:DI 0 "push_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "!TARGET_64BIT && reload_completed + && !(MMX_REG_P (operands[1]) || SSE_REG_P (operands[1]))" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") + +(define_insn "*pushsi2" [(set (match_operand:SI 0 "push_operand" "=<") (match_operand:SI 1 "general_no_elim_operand" "ri*m"))] "!TARGET_64BIT" @@ -1758,381 +1742,532 @@ [(set_attr "type" "push") (set_attr "mode" "SI")]) +;; emit_push_insn when it calls move_by_pieces requires an insn to +;; "push a byte/word". But actually we use pushl, which has the effect +;; of rounding the amount pushed up to a word. + ;; For 64BIT abi we always round up to 8 bytes. -(define_insn "*pushsi2_rex64" - [(set (match_operand:SI 0 "push_operand" "=X") - (match_operand:SI 1 "nonmemory_no_elim_operand" "ri"))] +(define_insn "*push2_rex64" + [(set (match_operand:SWI124 0 "push_operand" "=X") + (match_operand:SWI124 1 "nonmemory_no_elim_operand" "r"))] "TARGET_64BIT" "push{q}\t%q1" [(set_attr "type" "push") - (set_attr "mode" "SI")]) + (set_attr "mode" "DI")]) -(define_insn "*pushsi2_prologue" - [(set (match_operand:SI 0 "push_operand" "=<") - (match_operand:SI 1 "general_no_elim_operand" "ri*m")) - (clobber (mem:BLK (scratch)))] +(define_insn "*push2" + [(set (match_operand:SWI12 0 "push_operand" "=X") + (match_operand:SWI12 1 "nonmemory_no_elim_operand" "rn"))] "!TARGET_64BIT" - "push{l}\t%1" + "push{l}\t%k1" [(set_attr "type" "push") (set_attr "mode" "SI")]) -(define_insn "*popsi1_epilogue" +(define_insn "*push2_prologue" + [(set (match_operand:P 0 "push_operand" "=<") + (match_operand:P 1 "general_no_elim_operand" "r*m")) + (clobber (mem:BLK (scratch)))] + "" + "push{}\t%1" + [(set_attr "type" "push") + (set_attr "mode" "")]) + +(define_insn "popdi1" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r*m") + (mem:DI (reg:DI SP_REG))) + (set (reg:DI SP_REG) + (plus:DI (reg:DI SP_REG) (const_int 8)))] + "TARGET_64BIT" + "pop{q}\t%0" + [(set_attr "type" "pop") + (set_attr "mode" "DI")]) + +(define_insn "popsi1" [(set (match_operand:SI 0 "nonimmediate_operand" "=r*m") (mem:SI (reg:SI SP_REG))) (set (reg:SI SP_REG) - (plus:SI (reg:SI SP_REG) (const_int 4))) - (clobber (mem:BLK (scratch)))] + (plus:SI (reg:SI SP_REG) (const_int 4)))] "!TARGET_64BIT" "pop{l}\t%0" [(set_attr "type" "pop") (set_attr "mode" "SI")]) -(define_insn "popsi1" +(define_insn "*popdi1_epilogue" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r*m") + (mem:DI (reg:DI SP_REG))) + (set (reg:DI SP_REG) + (plus:DI (reg:DI SP_REG) (const_int 8))) + (clobber (mem:BLK (scratch)))] + "TARGET_64BIT" + "pop{q}\t%0" + [(set_attr "type" "pop") + (set_attr "mode" "DI")]) + +(define_insn "*popsi1_epilogue" [(set (match_operand:SI 0 "nonimmediate_operand" "=r*m") (mem:SI (reg:SI SP_REG))) (set (reg:SI SP_REG) - (plus:SI (reg:SI SP_REG) (const_int 4)))] + (plus:SI (reg:SI SP_REG) (const_int 4))) + (clobber (mem:BLK (scratch)))] "!TARGET_64BIT" "pop{l}\t%0" [(set_attr "type" "pop") (set_attr "mode" "SI")]) -(define_insn "*movsi_xor" - [(set (match_operand:SI 0 "register_operand" "=r") - (match_operand:SI 1 "const0_operand" "")) +(define_insn "*mov_xor" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (match_operand:SWI48 1 "const0_operand" "")) (clobber (reg:CC FLAGS_REG))] "reload_completed" - "xor{l}\t%0, %0" + "xor{l}\t%k0, %k0" [(set_attr "type" "alu1") (set_attr "mode" "SI") (set_attr "length_immediate" "0")]) -(define_insn "*movsi_or" - [(set (match_operand:SI 0 "register_operand" "=r") - (match_operand:SI 1 "immediate_operand" "i")) +(define_insn "*mov_or" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (match_operand:SWI48 1 "const_int_operand" "")) (clobber (reg:CC FLAGS_REG))] "reload_completed && operands[1] == constm1_rtx" -{ - operands[1] = constm1_rtx; - return "or{l}\t{%1, %0|%0, %1}"; -} + "or{}\t{%1, %0|%0, %1}" [(set_attr "type" "alu1") - (set_attr "mode" "SI") + (set_attr "mode" "") (set_attr "length_immediate" "1")]) -(define_insn "*movsi_1" - [(set (match_operand:SI 0 "nonimmediate_operand" - "=r,m ,*y,*y,?rm,?*y,*x,*x,?r ,m ,?*Yi,*x") - (match_operand:SI 1 "general_operand" - "g ,ri,C ,*y,*y ,rm ,C ,*x,*Yi,*x,r ,m "))] - "!(MEM_P (operands[0]) && MEM_P (operands[1]))" +(define_insn "*movoi_internal_avx" + [(set (match_operand:OI 0 "nonimmediate_operand" "=x,x,m") + (match_operand:OI 1 "vector_move_operand" "C,xm,x"))] + "TARGET_AVX && !(MEM_P (operands[0]) && MEM_P (operands[1]))" { - switch (get_attr_type (insn)) + switch (which_alternative) { - case TYPE_SSELOG1: - if (get_attr_mode (insn) == MODE_TI) - return "%vpxor\t%0, %d0"; - return "%vxorps\t%0, %d0"; + case 0: + return "vxorps\t%0, %0, %0"; + case 1: + case 2: + if (misaligned_operand (operands[0], OImode) + || misaligned_operand (operands[1], OImode)) + return "vmovdqu\t{%1, %0|%0, %1}"; + else + return "vmovdqa\t{%1, %0|%0, %1}"; + default: + gcc_unreachable (); + } +} + [(set_attr "type" "sselog1,ssemov,ssemov") + (set_attr "prefix" "vex") + (set_attr "mode" "OI")]) - case TYPE_SSEMOV: - switch (get_attr_mode (insn)) +(define_insn "*movti_internal_rex64" + [(set (match_operand:TI 0 "nonimmediate_operand" "=!r,o,x,x,xm") + (match_operand:TI 1 "general_operand" "riFo,riF,C,xm,x"))] + "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))" +{ + switch (which_alternative) + { + case 0: + case 1: + return "#"; + case 2: + if (get_attr_mode (insn) == MODE_V4SF) + return "%vxorps\t%0, %d0"; + else + return "%vpxor\t%0, %d0"; + case 3: + case 4: + /* TDmode values are passed as TImode on the stack. Moving them + to stack may result in unaligned memory access. */ + if (misaligned_operand (operands[0], TImode) + || misaligned_operand (operands[1], TImode)) { - case MODE_TI: - return "%vmovdqa\t{%1, %0|%0, %1}"; - case MODE_V4SF: - return "%vmovaps\t{%1, %0|%0, %1}"; - case MODE_SI: - return "%vmovd\t{%1, %0|%0, %1}"; - case MODE_SF: - return "%vmovss\t{%1, %0|%0, %1}"; - default: - gcc_unreachable (); + if (get_attr_mode (insn) == MODE_V4SF) + return "%vmovups\t{%1, %0|%0, %1}"; + else + return "%vmovdqu\t{%1, %0|%0, %1}"; + } + else + { + if (get_attr_mode (insn) == MODE_V4SF) + return "%vmovaps\t{%1, %0|%0, %1}"; + else + return "%vmovdqa\t{%1, %0|%0, %1}"; } - - case TYPE_MMX: - return "pxor\t%0, %0"; - - case TYPE_MMXMOV: - if (get_attr_mode (insn) == MODE_DI) - return "movq\t{%1, %0|%0, %1}"; - return "movd\t{%1, %0|%0, %1}"; - - case TYPE_LEA: - return "lea{l}\t{%1, %0|%0, %1}"; - default: - gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1])); - return "mov{l}\t{%1, %0|%0, %1}"; + gcc_unreachable (); } } - [(set (attr "type") - (cond [(eq_attr "alternative" "2") - (const_string "mmx") - (eq_attr "alternative" "3,4,5") - (const_string "mmxmov") - (eq_attr "alternative" "6") - (const_string "sselog1") - (eq_attr "alternative" "7,8,9,10,11") - (const_string "ssemov") - (match_operand:DI 1 "pic_32bit_operand" "") - (const_string "lea") - ] - (const_string "imov"))) - (set (attr "prefix") - (if_then_else (eq_attr "alternative" "0,1,2,3,4,5") - (const_string "orig") - (const_string "maybe_vex"))) - (set (attr "prefix_data16") - (if_then_else (and (eq_attr "type" "ssemov") (eq_attr "mode" "SI")) - (const_string "1") - (const_string "*"))) + [(set_attr "type" "*,*,sselog1,ssemov,ssemov") + (set_attr "prefix" "*,*,maybe_vex,maybe_vex,maybe_vex") (set (attr "mode") - (cond [(eq_attr "alternative" "2,3") - (const_string "DI") - (eq_attr "alternative" "6,7") - (if_then_else - (eq (symbol_ref "TARGET_SSE2") (const_int 0)) - (const_string "V4SF") - (const_string "TI")) - (and (eq_attr "alternative" "8,9,10,11") - (eq (symbol_ref "TARGET_SSE2") (const_int 0))) - (const_string "SF") - ] - (const_string "SI")))]) + (cond [(eq_attr "alternative" "2,3") + (if_then_else + (ne (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0)) + (const_string "V4SF") + (const_string "TI")) + (eq_attr "alternative" "4") + (if_then_else + (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") + (const_int 0)) + (ne (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "V4SF") + (const_string "TI"))] + (const_string "DI")))]) -;; Stores and loads of ax to arbitrary constant address. -;; We fake an second form of instruction to force reload to load address -;; into register when rax is not available -(define_insn "*movabssi_1_rex64" - [(set (mem:SI (match_operand:DI 0 "x86_64_movabs_operand" "i,r")) - (match_operand:SI 1 "nonmemory_operand" "a,er"))] - "TARGET_64BIT && ix86_check_movabs (insn, 0)" - "@ - movabs{l}\t{%1, %P0|%P0, %1} - mov{l}\t{%1, %a0|%a0, %1}" - [(set_attr "type" "imov") - (set_attr "modrm" "0,*") - (set_attr "length_address" "8,0") - (set_attr "length_immediate" "0,*") - (set_attr "memory" "store") - (set_attr "mode" "SI")]) +(define_split + [(set (match_operand:TI 0 "nonimmediate_operand" "") + (match_operand:TI 1 "general_operand" ""))] + "reload_completed + && !SSE_REG_P (operands[0]) && !SSE_REG_P (operands[1])" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") -(define_insn "*movabssi_2_rex64" - [(set (match_operand:SI 0 "register_operand" "=a,r") - (mem:SI (match_operand:DI 1 "x86_64_movabs_operand" "i,r")))] - "TARGET_64BIT && ix86_check_movabs (insn, 1)" - "@ - movabs{l}\t{%P1, %0|%0, %P1} - mov{l}\t{%a1, %0|%0, %a1}" - [(set_attr "type" "imov") - (set_attr "modrm" "0,*") - (set_attr "length_address" "8,0") - (set_attr "length_immediate" "0") - (set_attr "memory" "load") - (set_attr "mode" "SI")]) +(define_insn "*movti_internal_sse" + [(set (match_operand:TI 0 "nonimmediate_operand" "=x,x,m") + (match_operand:TI 1 "vector_move_operand" "C,xm,x"))] + "TARGET_SSE && !TARGET_64BIT + && !(MEM_P (operands[0]) && MEM_P (operands[1]))" +{ + switch (which_alternative) + { + case 0: + if (get_attr_mode (insn) == MODE_V4SF) + return "%vxorps\t%0, %d0"; + else + return "%vpxor\t%0, %d0"; + case 1: + case 2: + /* TDmode values are passed as TImode on the stack. Moving them + to stack may result in unaligned memory access. */ + if (misaligned_operand (operands[0], TImode) + || misaligned_operand (operands[1], TImode)) + { + if (get_attr_mode (insn) == MODE_V4SF) + return "%vmovups\t{%1, %0|%0, %1}"; + else + return "%vmovdqu\t{%1, %0|%0, %1}"; + } + else + { + if (get_attr_mode (insn) == MODE_V4SF) + return "%vmovaps\t{%1, %0|%0, %1}"; + else + return "%vmovdqa\t{%1, %0|%0, %1}"; + } + default: + gcc_unreachable (); + } +} + [(set_attr "type" "sselog1,ssemov,ssemov") + (set_attr "prefix" "maybe_vex") + (set (attr "mode") + (cond [(ior (eq (symbol_ref "TARGET_SSE2") (const_int 0)) + (ne (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "V4SF") + (and (eq_attr "alternative" "2") + (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") + (const_int 0))) + (const_string "V4SF")] + (const_string "TI")))]) -(define_insn "*swapsi" - [(set (match_operand:SI 0 "register_operand" "+r") - (match_operand:SI 1 "register_operand" "+r")) - (set (match_dup 1) - (match_dup 0))] - "" - "xchg{l}\t%1, %0" - [(set_attr "type" "imov") - (set_attr "mode" "SI") - (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector") - (set_attr "amdfam10_decode" "double")]) +(define_insn "*movdi_internal_rex64" + [(set (match_operand:DI 0 "nonimmediate_operand" + "=r,r ,r,m ,!m,*y,*y,?r ,m ,?*Ym,?*y,*x,*x,?r ,m,?*Yi,*x,?*x,?*Ym") + (match_operand:DI 1 "general_operand" + "Z ,rem,i,re,n ,C ,*y,*Ym,*y,r ,m ,C ,*x,*Yi,*x,r ,m ,*Ym,*x"))] + "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))" +{ + switch (get_attr_type (insn)) + { + case TYPE_SSECVT: + if (SSE_REG_P (operands[0])) + return "movq2dq\t{%1, %0|%0, %1}"; + else + return "movdq2q\t{%1, %0|%0, %1}"; -(define_expand "movhi" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (match_operand:HI 1 "general_operand" ""))] - "" - "ix86_expand_move (HImode, operands); DONE;") + case TYPE_SSEMOV: + if (TARGET_AVX) + { + if (get_attr_mode (insn) == MODE_TI) + return "vmovdqa\t{%1, %0|%0, %1}"; + else + return "vmovq\t{%1, %0|%0, %1}"; + } -(define_insn "*pushhi2" - [(set (match_operand:HI 0 "push_operand" "=X") - (match_operand:HI 1 "nonmemory_no_elim_operand" "rn"))] - "!TARGET_64BIT" - "push{l}\t%k1" - [(set_attr "type" "push") - (set_attr "mode" "SI")]) + if (get_attr_mode (insn) == MODE_TI) + return "movdqa\t{%1, %0|%0, %1}"; + /* FALLTHRU */ -;; For 64BIT abi we always round up to 8 bytes. -(define_insn "*pushhi2_rex64" - [(set (match_operand:HI 0 "push_operand" "=X") - (match_operand:HI 1 "nonmemory_no_elim_operand" "rn"))] - "TARGET_64BIT" - "push{q}\t%q1" - [(set_attr "type" "push") - (set_attr "mode" "DI")]) + case TYPE_MMXMOV: + /* Moves from and into integer register is done using movd + opcode with REX prefix. */ + if (GENERAL_REG_P (operands[0]) || GENERAL_REG_P (operands[1])) + return "movd\t{%1, %0|%0, %1}"; + return "movq\t{%1, %0|%0, %1}"; + + case TYPE_SSELOG1: + return "%vpxor\t%0, %d0"; + + case TYPE_MMX: + return "pxor\t%0, %0"; + + case TYPE_MULTI: + return "#"; + + case TYPE_LEA: + return "lea{q}\t{%a1, %0|%0, %a1}"; -(define_insn "*movhi_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m") - (match_operand:HI 1 "general_operand" "r,rn,rm,rn"))] - "!(MEM_P (operands[0]) && MEM_P (operands[1]))" -{ - switch (get_attr_type (insn)) - { - case TYPE_IMOVX: - /* movzwl is faster than movw on p2 due to partial word stalls, - though not as fast as an aligned movl. */ - return "movz{wl|x}\t{%1, %k0|%k0, %1}"; default: + gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1])); if (get_attr_mode (insn) == MODE_SI) - return "mov{l}\t{%k1, %k0|%k0, %k1}"; + return "mov{l}\t{%k1, %k0|%k0, %k1}"; + else if (which_alternative == 2) + return "movabs{q}\t{%1, %0|%0, %1}"; else - return "mov{w}\t{%1, %0|%0, %1}"; + return "mov{q}\t{%1, %0|%0, %1}"; } } [(set (attr "type") - (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) - (const_string "imov") - (and (eq_attr "alternative" "0") - (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") - (const_int 0)) - (eq (symbol_ref "TARGET_HIMODE_MATH") - (const_int 0)))) - (const_string "imov") - (and (eq_attr "alternative" "1,2") - (match_operand:HI 1 "aligned_operand" "")) - (const_string "imov") - (and (ne (symbol_ref "TARGET_MOVX") - (const_int 0)) - (eq_attr "alternative" "0,2")) - (const_string "imovx") + (cond [(eq_attr "alternative" "5") + (const_string "mmx") + (eq_attr "alternative" "6,7,8,9,10") + (const_string "mmxmov") + (eq_attr "alternative" "11") + (const_string "sselog1") + (eq_attr "alternative" "12,13,14,15,16") + (const_string "ssemov") + (eq_attr "alternative" "17,18") + (const_string "ssecvt") + (eq_attr "alternative" "4") + (const_string "multi") + (match_operand:DI 1 "pic_32bit_operand" "") + (const_string "lea") ] (const_string "imov"))) - (set (attr "mode") - (cond [(eq_attr "type" "imovx") - (const_string "SI") - (and (eq_attr "alternative" "1,2") - (match_operand:HI 1 "aligned_operand" "")) - (const_string "SI") - (and (eq_attr "alternative" "0") - (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") - (const_int 0)) - (eq (symbol_ref "TARGET_HIMODE_MATH") - (const_int 0)))) - (const_string "SI") - ] - (const_string "HI")))]) - -;; Stores and loads of ax to arbitrary constant address. -;; We fake an second form of instruction to force reload to load address -;; into register when rax is not available -(define_insn "*movabshi_1_rex64" - [(set (mem:HI (match_operand:DI 0 "x86_64_movabs_operand" "i,r")) - (match_operand:HI 1 "nonmemory_operand" "a,er"))] - "TARGET_64BIT && ix86_check_movabs (insn, 0)" - "@ - movabs{w}\t{%1, %P0|%P0, %1} - mov{w}\t{%1, %a0|%a0, %1}" - [(set_attr "type" "imov") - (set_attr "modrm" "0,*") - (set_attr "length_address" "8,0") - (set_attr "length_immediate" "0,*") - (set_attr "memory" "store") - (set_attr "mode" "HI")]) + (set (attr "modrm") + (if_then_else + (and (eq_attr "alternative" "2") (eq_attr "type" "imov")) + (const_string "0") + (const_string "*"))) + (set (attr "length_immediate") + (if_then_else + (and (eq_attr "alternative" "2") (eq_attr "type" "imov")) + (const_string "8") + (const_string "*"))) + (set_attr "prefix_rex" "*,*,*,*,*,*,*,1,*,1,*,*,*,*,*,*,*,*,*") + (set_attr "prefix_data16" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,1,*,*,*") + (set (attr "prefix") + (if_then_else (eq_attr "alternative" "11,12,13,14,15,16") + (const_string "maybe_vex") + (const_string "orig"))) + (set_attr "mode" "SI,DI,DI,DI,SI,DI,DI,DI,DI,DI,DI,TI,TI,DI,DI,DI,DI,DI,DI")]) -(define_insn "*movabshi_2_rex64" - [(set (match_operand:HI 0 "register_operand" "=a,r") - (mem:HI (match_operand:DI 1 "x86_64_movabs_operand" "i,r")))] - "TARGET_64BIT && ix86_check_movabs (insn, 1)" - "@ - movabs{w}\t{%P1, %0|%0, %P1} - mov{w}\t{%a1, %0|%0, %a1}" - [(set_attr "type" "imov") - (set_attr "modrm" "0,*") - (set_attr "length_address" "8,0") - (set_attr "length_immediate" "0") - (set_attr "memory" "load") - (set_attr "mode" "HI")]) +;; Convert impossible stores of immediate to existing instructions. +;; First try to get scratch register and go through it. In case this +;; fails, move by 32bit parts. +(define_peephole2 + [(match_scratch:DI 2 "r") + (set (match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode)" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (match_dup 2))] + "") -(define_insn "*swaphi_1" - [(set (match_operand:HI 0 "register_operand" "+r") - (match_operand:HI 1 "register_operand" "+r")) - (set (match_dup 1) - (match_dup 0))] - "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" - "xchg{l}\t%k1, %k0" - [(set_attr "type" "imov") - (set_attr "mode" "SI") - (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector") - (set_attr "amdfam10_decode" "double")]) +;; We need to define this as both peepholer and splitter for case +;; peephole2 pass is not run. +;; "&& 1" is needed to keep it from matching the previous pattern. +(define_peephole2 + [(set (match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode) && 1" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 5))] + "split_di (&operands[0], 2, &operands[2], &operands[4]);") -;; Not added amdfam10_decode since TARGET_PARTIAL_REG_STALL is disabled for AMDFAM10 -(define_insn "*swaphi_2" - [(set (match_operand:HI 0 "register_operand" "+r") - (match_operand:HI 1 "register_operand" "+r")) - (set (match_dup 1) - (match_dup 0))] - "TARGET_PARTIAL_REG_STALL" - "xchg{w}\t%1, %0" - [(set_attr "type" "imov") - (set_attr "mode" "HI") - (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector")]) +(define_split + [(set (match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "immediate_operand" ""))] + "TARGET_64BIT && ((optimize > 0 && flag_peephole2) + ? epilogue_completed : reload_completed) + && !symbolic_operand (operands[1], DImode) + && !x86_64_immediate_operand (operands[1], DImode)" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 5))] + "split_di (&operands[0], 2, &operands[2], &operands[4]);") -(define_expand "movstricthi" - [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "")) - (match_operand:HI 1 "general_operand" ""))] - "" +(define_insn "*movdi_internal" + [(set (match_operand:DI 0 "nonimmediate_operand" + "=r ,o ,*y,m*y,*y,*Y2,m ,*Y2,*Y2,*x,m ,*x,*x") + (match_operand:DI 1 "general_operand" + "riFo,riF,C ,*y ,m ,C ,*Y2,*Y2,m ,C ,*x,*x,m "))] + "!TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))" + "@ + # + # + pxor\t%0, %0 + movq\t{%1, %0|%0, %1} + movq\t{%1, %0|%0, %1} + %vpxor\t%0, %d0 + %vmovq\t{%1, %0|%0, %1} + %vmovdqa\t{%1, %0|%0, %1} + %vmovq\t{%1, %0|%0, %1} + xorps\t%0, %0 + movlps\t{%1, %0|%0, %1} + movaps\t{%1, %0|%0, %1} + movlps\t{%1, %0|%0, %1}" + [(set_attr "type" "*,*,mmx,mmxmov,mmxmov,sselog1,ssemov,ssemov,ssemov,sselog1,ssemov,ssemov,ssemov") + (set (attr "prefix") + (if_then_else (eq_attr "alternative" "5,6,7,8") + (const_string "vex") + (const_string "orig"))) + (set_attr "mode" "DI,DI,DI,DI,DI,TI,DI,TI,DI,V4SF,V2SF,V4SF,V2SF")]) + +(define_split + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "!TARGET_64BIT && reload_completed + && !(MMX_REG_P (operands[0]) || SSE_REG_P (operands[0])) + && !(MMX_REG_P (operands[1]) || SSE_REG_P (operands[1]))" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") + +(define_insn "*movsi_internal" + [(set (match_operand:SI 0 "nonimmediate_operand" + "=r,m ,*y,*y,?rm,?*y,*x,*x,?r ,m ,?*Yi,*x") + (match_operand:SI 1 "general_operand" + "g ,ri,C ,*y,*y ,rm ,C ,*x,*Yi,*x,r ,m "))] + "!(MEM_P (operands[0]) && MEM_P (operands[1]))" { - if (TARGET_PARTIAL_REG_STALL && optimize_function_for_speed_p (cfun)) - FAIL; - /* Don't generate memory->memory moves, go through a register */ - if (MEM_P (operands[0]) && MEM_P (operands[1])) - operands[1] = force_reg (HImode, operands[1]); -}) + switch (get_attr_type (insn)) + { + case TYPE_SSELOG1: + if (get_attr_mode (insn) == MODE_TI) + return "%vpxor\t%0, %d0"; + return "%vxorps\t%0, %d0"; -(define_insn "*movstricthi_1" - [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+rm,r")) - (match_operand:HI 1 "general_operand" "rn,m"))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "mov{w}\t{%1, %0|%0, %1}" - [(set_attr "type" "imov") - (set_attr "mode" "HI")]) + case TYPE_SSEMOV: + switch (get_attr_mode (insn)) + { + case MODE_TI: + return "%vmovdqa\t{%1, %0|%0, %1}"; + case MODE_V4SF: + return "%vmovaps\t{%1, %0|%0, %1}"; + case MODE_SI: + return "%vmovd\t{%1, %0|%0, %1}"; + case MODE_SF: + return "%vmovss\t{%1, %0|%0, %1}"; + default: + gcc_unreachable (); + } -(define_insn "*movstricthi_xor" - [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r")) - (match_operand:HI 1 "const0_operand" "")) - (clobber (reg:CC FLAGS_REG))] - "reload_completed" - "xor{w}\t%0, %0" - [(set_attr "type" "alu1") - (set_attr "mode" "HI") - (set_attr "length_immediate" "0")]) + case TYPE_MMX: + return "pxor\t%0, %0"; -(define_expand "movqi" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (match_operand:QI 1 "general_operand" ""))] - "" - "ix86_expand_move (QImode, operands); DONE;") + case TYPE_MMXMOV: + if (get_attr_mode (insn) == MODE_DI) + return "movq\t{%1, %0|%0, %1}"; + return "movd\t{%1, %0|%0, %1}"; -;; emit_push_insn when it calls move_by_pieces requires an insn to -;; "push a byte". But actually we use pushl, which has the effect -;; of rounding the amount pushed up to a word. + case TYPE_LEA: + return "lea{l}\t{%a1, %0|%0, %a1}"; -(define_insn "*pushqi2" - [(set (match_operand:QI 0 "push_operand" "=X") - (match_operand:QI 1 "nonmemory_no_elim_operand" "rn"))] - "!TARGET_64BIT" - "push{l}\t%k1" - [(set_attr "type" "push") - (set_attr "mode" "SI")]) + default: + gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1])); + return "mov{l}\t{%1, %0|%0, %1}"; + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "2") + (const_string "mmx") + (eq_attr "alternative" "3,4,5") + (const_string "mmxmov") + (eq_attr "alternative" "6") + (const_string "sselog1") + (eq_attr "alternative" "7,8,9,10,11") + (const_string "ssemov") + (match_operand:DI 1 "pic_32bit_operand" "") + (const_string "lea") + ] + (const_string "imov"))) + (set (attr "prefix") + (if_then_else (eq_attr "alternative" "0,1,2,3,4,5") + (const_string "orig") + (const_string "maybe_vex"))) + (set (attr "prefix_data16") + (if_then_else (and (eq_attr "type" "ssemov") (eq_attr "mode" "SI")) + (const_string "1") + (const_string "*"))) + (set (attr "mode") + (cond [(eq_attr "alternative" "2,3") + (const_string "DI") + (eq_attr "alternative" "6,7") + (if_then_else + (eq (symbol_ref "TARGET_SSE2") (const_int 0)) + (const_string "V4SF") + (const_string "TI")) + (and (eq_attr "alternative" "8,9,10,11") + (eq (symbol_ref "TARGET_SSE2") (const_int 0))) + (const_string "SF") + ] + (const_string "SI")))]) -;; For 64BIT abi we always round up to 8 bytes. -(define_insn "*pushqi2_rex64" - [(set (match_operand:QI 0 "push_operand" "=X") - (match_operand:QI 1 "nonmemory_no_elim_operand" "qn"))] - "TARGET_64BIT" - "push{q}\t%q1" - [(set_attr "type" "push") - (set_attr "mode" "DI")]) +(define_insn "*movhi_internal" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m") + (match_operand:HI 1 "general_operand" "r,rn,rm,rn"))] + "!(MEM_P (operands[0]) && MEM_P (operands[1]))" +{ + switch (get_attr_type (insn)) + { + case TYPE_IMOVX: + /* movzwl is faster than movw on p2 due to partial word stalls, + though not as fast as an aligned movl. */ + return "movz{wl|x}\t{%1, %k0|%k0, %1}"; + default: + if (get_attr_mode (insn) == MODE_SI) + return "mov{l}\t{%k1, %k0|%k0, %k1}"; + else + return "mov{w}\t{%1, %0|%0, %1}"; + } +} + [(set (attr "type") + (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0)) + (const_string "imov") + (and (eq_attr "alternative" "0") + (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") + (const_int 0)) + (eq (symbol_ref "TARGET_HIMODE_MATH") + (const_int 0)))) + (const_string "imov") + (and (eq_attr "alternative" "1,2") + (match_operand:HI 1 "aligned_operand" "")) + (const_string "imov") + (and (ne (symbol_ref "TARGET_MOVX") + (const_int 0)) + (eq_attr "alternative" "0,2")) + (const_string "imovx") + ] + (const_string "imov"))) + (set (attr "mode") + (cond [(eq_attr "type" "imovx") + (const_string "SI") + (and (eq_attr "alternative" "1,2") + (match_operand:HI 1 "aligned_operand" "")) + (const_string "SI") + (and (eq_attr "alternative" "0") + (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") + (const_int 0)) + (eq (symbol_ref "TARGET_HIMODE_MATH") + (const_int 0)))) + (const_string "SI") + ] + (const_string "HI")))]) ;; Situation is quite tricky about when to choose full sized (SImode) move ;; over QImode moves. For Q_REG -> Q_REG move we use full size only for @@ -2144,7 +2279,7 @@ ;; For loads of Q_REG to NONQ_REG we use full sized moves except for partial ;; register stall machines with, where we use QImode instructions, since ;; partial register stall can be caused there. Then we use movzx. -(define_insn "*movqi_1" +(define_insn "*movqi_internal" [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q ,q ,r,r ,?r,m") (match_operand:QI 1 "general_operand" " q,qn,qm,q,rn,qm,qn"))] "!(MEM_P (operands[0]) && MEM_P (operands[1]))" @@ -2165,7 +2300,8 @@ (cond [(and (eq_attr "alternative" "5") (not (match_operand:QI 1 "aligned_operand" ""))) (const_string "imovx") - (ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) + (ne (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0)) (const_string "imov") (and (eq_attr "alternative" "3") (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") @@ -2194,7 +2330,7 @@ (const_int 0)) (and (eq (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0)) - (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") + (eq (symbol_ref "TARGET_PARTIAL_REG_STALL") (const_int 0)))))) (const_string "SI") ;; Avoid partial register stalls when not using QImode arithmetic @@ -2208,89 +2344,125 @@ ] (const_string "QI")))]) -(define_insn "*swapqi_1" - [(set (match_operand:QI 0 "register_operand" "+r") - (match_operand:QI 1 "register_operand" "+r")) - (set (match_dup 1) - (match_dup 0))] - "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" - "xchg{l}\t%k1, %k0" +;; Stores and loads of ax to arbitrary constant address. +;; We fake an second form of instruction to force reload to load address +;; into register when rax is not available +(define_insn "*movabs_1" + [(set (mem:SWI1248x (match_operand:DI 0 "x86_64_movabs_operand" "i,r")) + (match_operand:SWI1248x 1 "nonmemory_operand" "a,er"))] + "TARGET_64BIT && ix86_check_movabs (insn, 0)" + "@ + movabs{}\t{%1, %P0|%P0, %1} + mov{}\t{%1, %a0|%a0, %1}" [(set_attr "type" "imov") - (set_attr "mode" "SI") - (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector") - (set_attr "amdfam10_decode" "vector")]) + (set_attr "modrm" "0,*") + (set_attr "length_address" "8,0") + (set_attr "length_immediate" "0,*") + (set_attr "memory" "store") + (set_attr "mode" "")]) -;; Not added amdfam10_decode since TARGET_PARTIAL_REG_STALL is disabled for AMDFAM10 -(define_insn "*swapqi_2" - [(set (match_operand:QI 0 "register_operand" "+q") - (match_operand:QI 1 "register_operand" "+q")) - (set (match_dup 1) - (match_dup 0))] +(define_insn "*movabs_2" + [(set (match_operand:SWI1248x 0 "register_operand" "=a,r") + (mem:SWI1248x (match_operand:DI 1 "x86_64_movabs_operand" "i,r")))] + "TARGET_64BIT && ix86_check_movabs (insn, 1)" + "@ + movabs{}\t{%P1, %0|%0, %P1} + mov{}\t{%a1, %0|%0, %a1}" + [(set_attr "type" "imov") + (set_attr "modrm" "0,*") + (set_attr "length_address" "8,0") + (set_attr "length_immediate" "0") + (set_attr "memory" "load") + (set_attr "mode" "")]) + +(define_insn "*swap" + [(set (match_operand:SWI48 0 "register_operand" "+r") + (match_operand:SWI48 1 "register_operand" "+r")) + (set (match_dup 1) + (match_dup 0))] + "" + "xchg{}\t%1, %0" + [(set_attr "type" "imov") + (set_attr "mode" "") + (set_attr "pent_pair" "np") + (set_attr "athlon_decode" "vector") + (set_attr "amdfam10_decode" "double")]) + +(define_insn "*swap_1" + [(set (match_operand:SWI12 0 "register_operand" "+r") + (match_operand:SWI12 1 "register_operand" "+r")) + (set (match_dup 1) + (match_dup 0))] + "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" + "xchg{l}\t%k1, %k0" + [(set_attr "type" "imov") + (set_attr "mode" "SI") + (set_attr "pent_pair" "np") + (set_attr "athlon_decode" "vector") + (set_attr "amdfam10_decode" "double")]) + +;; Not added amdfam10_decode since TARGET_PARTIAL_REG_STALL +;; is disabled for AMDFAM10 +(define_insn "*swap_2" + [(set (match_operand:SWI12 0 "register_operand" "+") + (match_operand:SWI12 1 "register_operand" "+")) + (set (match_dup 1) + (match_dup 0))] "TARGET_PARTIAL_REG_STALL" - "xchg{b}\t%1, %0" + "xchg{}\t%1, %0" [(set_attr "type" "imov") - (set_attr "mode" "QI") + (set_attr "mode" "") (set_attr "pent_pair" "np") (set_attr "athlon_decode" "vector")]) -(define_expand "movstrictqi" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "")) - (match_operand:QI 1 "general_operand" ""))] +(define_expand "movstrict" + [(set (strict_low_part (match_operand:SWI12 0 "nonimmediate_operand" "")) + (match_operand:SWI12 1 "general_operand" ""))] "" { if (TARGET_PARTIAL_REG_STALL && optimize_function_for_speed_p (cfun)) FAIL; - /* Don't generate memory->memory moves, go through a register. */ + /* Don't generate memory->memory moves, go through a register */ if (MEM_P (operands[0]) && MEM_P (operands[1])) - operands[1] = force_reg (QImode, operands[1]); + operands[1] = force_reg (mode, operands[1]); }) -(define_insn "*movstrictqi_1" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) - (match_operand:QI 1 "general_operand" "*qn,m"))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) +(define_insn "*movstrict_1" + [(set (strict_low_part + (match_operand:SWI12 0 "nonimmediate_operand" "+m,")) + (match_operand:SWI12 1 "general_operand" "n,m"))] + "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "mov{b}\t{%1, %0|%0, %1}" + "mov{}\t{%1, %0|%0, %1}" [(set_attr "type" "imov") - (set_attr "mode" "QI")]) + (set_attr "mode" "")]) -(define_insn "*movstrictqi_xor" - [(set (strict_low_part (match_operand:QI 0 "q_regs_operand" "+q")) - (match_operand:QI 1 "const0_operand" "")) +(define_insn "*movstrict_xor" + [(set (strict_low_part (match_operand:SWI12 0 "register_operand" "+")) + (match_operand:SWI12 1 "const0_operand" "")) (clobber (reg:CC FLAGS_REG))] "reload_completed" - "xor{b}\t%0, %0" + "xor{}\t%0, %0" [(set_attr "type" "alu1") - (set_attr "mode" "QI") + (set_attr "mode" "") (set_attr "length_immediate" "0")]) -(define_insn "*movsi_extv_1" - [(set (match_operand:SI 0 "register_operand" "=R") - (sign_extract:SI (match_operand 1 "ext_register_operand" "Q") - (const_int 8) - (const_int 8)))] - "" - "movs{bl|x}\t{%h1, %0|%0, %h1}" - [(set_attr "type" "imovx") - (set_attr "mode" "SI")]) - -(define_insn "*movhi_extv_1" - [(set (match_operand:HI 0 "register_operand" "=R") - (sign_extract:HI (match_operand 1 "ext_register_operand" "Q") - (const_int 8) - (const_int 8)))] +(define_insn "*mov_extv_1" + [(set (match_operand:SWI24 0 "register_operand" "=R") + (sign_extract:SWI24 (match_operand 1 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)))] "" "movs{bl|x}\t{%h1, %k0|%k0, %h1}" [(set_attr "type" "imovx") (set_attr "mode" "SI")]) -(define_insn "*movqi_extv_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=Qm,?r") +(define_insn "*movqi_extv_1_rex64" + [(set (match_operand:QI 0 "register_operand" "=Q,?R") (sign_extract:QI (match_operand 1 "ext_register_operand" "Q,Q") (const_int 8) (const_int 8)))] - "!TARGET_64BIT" + "TARGET_64BIT" { switch (get_attr_type (insn)) { @@ -2312,12 +2484,12 @@ (const_string "SI") (const_string "QI")))]) -(define_insn "*movqi_extv_1_rex64" - [(set (match_operand:QI 0 "register_operand" "=Q,?R") +(define_insn "*movqi_extv_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=Qm,?r") (sign_extract:QI (match_operand 1 "ext_register_operand" "Q,Q") (const_int 8) (const_int 8)))] - "TARGET_64BIT" + "!TARGET_64BIT" { switch (get_attr_type (insn)) { @@ -2339,63 +2511,23 @@ (const_string "SI") (const_string "QI")))]) -;; Stores and loads of ax to arbitrary constant address. -;; We fake an second form of instruction to force reload to load address -;; into register when rax is not available -(define_insn "*movabsqi_1_rex64" - [(set (mem:QI (match_operand:DI 0 "x86_64_movabs_operand" "i,r")) - (match_operand:QI 1 "nonmemory_operand" "a,er"))] - "TARGET_64BIT && ix86_check_movabs (insn, 0)" - "@ - movabs{b}\t{%1, %P0|%P0, %1} - mov{b}\t{%1, %a0|%a0, %1}" - [(set_attr "type" "imov") - (set_attr "modrm" "0,*") - (set_attr "length_address" "8,0") - (set_attr "length_immediate" "0,*") - (set_attr "memory" "store") - (set_attr "mode" "QI")]) - -(define_insn "*movabsqi_2_rex64" - [(set (match_operand:QI 0 "register_operand" "=a,r") - (mem:QI (match_operand:DI 1 "x86_64_movabs_operand" "i,r")))] - "TARGET_64BIT && ix86_check_movabs (insn, 1)" - "@ - movabs{b}\t{%P1, %0|%0, %P1} - mov{b}\t{%a1, %0|%0, %a1}" - [(set_attr "type" "imov") - (set_attr "modrm" "0,*") - (set_attr "length_address" "8,0") - (set_attr "length_immediate" "0") - (set_attr "memory" "load") - (set_attr "mode" "QI")]) - -(define_insn "*movdi_extzv_1" - [(set (match_operand:DI 0 "register_operand" "=R") - (zero_extract:DI (match_operand 1 "ext_register_operand" "Q") - (const_int 8) - (const_int 8)))] - "TARGET_64BIT" - "movz{bl|x}\t{%h1, %k0|%k0, %h1}" - [(set_attr "type" "imovx") - (set_attr "mode" "SI")]) - -(define_insn "*movsi_extzv_1" - [(set (match_operand:SI 0 "register_operand" "=R") - (zero_extract:SI (match_operand 1 "ext_register_operand" "Q") - (const_int 8) - (const_int 8)))] +(define_insn "*mov_extzv_1" + [(set (match_operand:SWI48 0 "register_operand" "=R") + (zero_extract:SWI48 (match_operand 1 "ext_register_operand" "Q") + (const_int 8) + (const_int 8)))] "" - "movz{bl|x}\t{%h1, %0|%0, %h1}" + "movz{bl|x}\t{%h1, %k0|%k0, %h1}" [(set_attr "type" "imovx") (set_attr "mode" "SI")]) -(define_insn "*movqi_extzv_2" - [(set (match_operand:QI 0 "nonimmediate_operand" "=Qm,?R") - (subreg:QI (zero_extract:SI (match_operand 1 "ext_register_operand" "Q,Q") - (const_int 8) - (const_int 8)) 0))] - "!TARGET_64BIT" +(define_insn "*movqi_extzv_2_rex64" + [(set (match_operand:QI 0 "register_operand" "=Q,?R") + (subreg:QI + (zero_extract:SI (match_operand 1 "ext_register_operand" "Q,Q") + (const_int 8) + (const_int 8)) 0))] + "TARGET_64BIT" { switch (get_attr_type (insn)) { @@ -2406,10 +2538,9 @@ } } [(set (attr "type") - (if_then_else (and (match_operand:QI 0 "register_operand" "") - (ior (not (match_operand:QI 0 "q_regs_operand" "")) - (ne (symbol_ref "TARGET_MOVX") - (const_int 0)))) + (if_then_else (ior (not (match_operand:QI 0 "q_regs_operand" "")) + (ne (symbol_ref "TARGET_MOVX") + (const_int 0))) (const_string "imovx") (const_string "imov"))) (set (attr "mode") @@ -2417,12 +2548,13 @@ (const_string "SI") (const_string "QI")))]) -(define_insn "*movqi_extzv_2_rex64" - [(set (match_operand:QI 0 "register_operand" "=Q,?R") - (subreg:QI (zero_extract:SI (match_operand 1 "ext_register_operand" "Q,Q") - (const_int 8) - (const_int 8)) 0))] - "TARGET_64BIT" +(define_insn "*movqi_extzv_2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=Qm,?R") + (subreg:QI + (zero_extract:SI (match_operand 1 "ext_register_operand" "Q,Q") + (const_int 8) + (const_int 8)) 0))] + "!TARGET_64BIT" { switch (get_attr_type (insn)) { @@ -2433,9 +2565,10 @@ } } [(set (attr "type") - (if_then_else (ior (not (match_operand:QI 0 "q_regs_operand" "")) - (ne (symbol_ref "TARGET_MOVX") - (const_int 0))) + (if_then_else (and (match_operand:QI 0 "register_operand" "") + (ior (not (match_operand:QI 0 "q_regs_operand" "")) + (ne (symbol_ref "TARGET_MOVX") + (const_int 0)))) (const_string "imovx") (const_string "imov"))) (set (attr "mode") @@ -2443,32 +2576,30 @@ (const_string "SI") (const_string "QI")))]) -(define_insn "movsi_insv_1" - [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q") - (const_int 8) - (const_int 8)) - (match_operand:SI 1 "general_operand" "Qmn"))] - "!TARGET_64BIT" - "mov{b}\t{%b1, %h0|%h0, %b1}" - [(set_attr "type" "imov") - (set_attr "mode" "QI")]) +(define_expand "mov_insv_1" + [(set (zero_extract:SWI48 (match_operand 0 "ext_register_operand" "") + (const_int 8) + (const_int 8)) + (match_operand:SWI48 1 "nonmemory_operand" ""))] + "" + "") -(define_insn "*movsi_insv_1_rex64" - [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q") - (const_int 8) - (const_int 8)) - (match_operand:SI 1 "nonmemory_operand" "Qn"))] +(define_insn "*mov_insv_1_rex64" + [(set (zero_extract:SWI48x (match_operand 0 "ext_register_operand" "+Q") + (const_int 8) + (const_int 8)) + (match_operand:SWI48x 1 "nonmemory_operand" "Qn"))] "TARGET_64BIT" "mov{b}\t{%b1, %h0|%h0, %b1}" [(set_attr "type" "imov") (set_attr "mode" "QI")]) -(define_insn "movdi_insv_1_rex64" - [(set (zero_extract:DI (match_operand 0 "ext_register_operand" "+Q") +(define_insn "*movsi_insv_1" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q") (const_int 8) (const_int 8)) - (match_operand:DI 1 "nonmemory_operand" "Qn"))] - "TARGET_64BIT" + (match_operand:SI 1 "general_operand" "Qmn"))] + "!TARGET_64BIT" "mov{b}\t{%b1, %h0|%h0, %b1}" [(set_attr "type" "imov") (set_attr "mode" "QI")]) @@ -2483,590 +2614,477 @@ "mov{b}\t{%h1, %h0|%h0, %h1}" [(set_attr "type" "imov") (set_attr "mode" "QI")]) + +;; Floating point move instructions. -(define_expand "movdi" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (match_operand:DI 1 "general_operand" ""))] +(define_expand "movtf" + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (match_operand:TF 1 "nonimmediate_operand" ""))] + "TARGET_SSE2" +{ + ix86_expand_move (TFmode, operands); + DONE; +}) + +(define_expand "mov" + [(set (match_operand:X87MODEF 0 "nonimmediate_operand" "") + (match_operand:X87MODEF 1 "general_operand" ""))] "" - "ix86_expand_move (DImode, operands); DONE;") + "ix86_expand_move (mode, operands); DONE;") -(define_insn "*pushdi" - [(set (match_operand:DI 0 "push_operand" "=<") - (match_operand:DI 1 "general_no_elim_operand" "riF*m"))] - "!TARGET_64BIT" - "#") +(define_insn "*pushtf" + [(set (match_operand:TF 0 "push_operand" "=<,<,<") + (match_operand:TF 1 "general_no_elim_operand" "x,Fo,*r"))] + "TARGET_SSE2" +{ + /* This insn should be already split before reg-stack. */ + gcc_unreachable (); +} + [(set_attr "type" "multi") + (set_attr "unit" "sse,*,*") + (set_attr "mode" "TF,SI,SI")]) -(define_insn "*pushdi2_rex64" - [(set (match_operand:DI 0 "push_operand" "=<,!<") - (match_operand:DI 1 "general_no_elim_operand" "re*m,n"))] - "TARGET_64BIT" - "@ - push{q}\t%1 - #" - [(set_attr "type" "push,multi") - (set_attr "mode" "DI")]) +(define_split + [(set (match_operand:TF 0 "push_operand" "") + (match_operand:TF 1 "general_operand" ""))] + "TARGET_SSE2 && reload_completed + && !SSE_REG_P (operands[1])" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") -;; Convert impossible pushes of immediate to existing instructions. -;; First try to get scratch register and go through it. In case this -;; fails, push sign extended lower part first and then overwrite -;; upper part by 32bit move. -(define_peephole2 - [(match_scratch:DI 2 "r") - (set (match_operand:DI 0 "push_operand" "") - (match_operand:DI 1 "immediate_operand" ""))] - "TARGET_64BIT && !symbolic_operand (operands[1], DImode) - && !x86_64_immediate_operand (operands[1], DImode)" - [(set (match_dup 2) (match_dup 1)) - (set (match_dup 0) (match_dup 2))] +(define_split + [(set (match_operand:TF 0 "push_operand" "") + (match_operand:TF 1 "any_fp_register_operand" ""))] + "TARGET_SSE2" + [(set (reg:P SP_REG) (plus:P (reg:P SP_REG) (const_int -16))) + (set (mem:TF (reg:P SP_REG)) (match_dup 1))] "") -;; We need to define this as both peepholer and splitter for case -;; peephole2 pass is not run. -;; "&& 1" is needed to keep it from matching the previous pattern. -(define_peephole2 - [(set (match_operand:DI 0 "push_operand" "") - (match_operand:DI 1 "immediate_operand" ""))] - "TARGET_64BIT && !symbolic_operand (operands[1], DImode) - && !x86_64_immediate_operand (operands[1], DImode) && 1" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 2) (match_dup 3))] - "split_di (&operands[1], 1, &operands[2], &operands[3]); - operands[1] = gen_lowpart (DImode, operands[2]); - operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (DImode, stack_pointer_rtx, - GEN_INT (4))); - ") +(define_insn "*pushxf" + [(set (match_operand:XF 0 "push_operand" "=<,<") + (match_operand:XF 1 "general_no_elim_operand" "f,ro"))] + "optimize_function_for_speed_p (cfun)" +{ + /* This insn should be already split before reg-stack. */ + gcc_unreachable (); +} + [(set_attr "type" "multi") + (set_attr "unit" "i387,*") + (set_attr "mode" "XF,SI")]) -(define_split - [(set (match_operand:DI 0 "push_operand" "") - (match_operand:DI 1 "immediate_operand" ""))] - "TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? epilogue_completed : reload_completed) - && !symbolic_operand (operands[1], DImode) - && !x86_64_immediate_operand (operands[1], DImode)" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 2) (match_dup 3))] - "split_di (&operands[1], 1, &operands[2], &operands[3]); - operands[1] = gen_lowpart (DImode, operands[2]); - operands[2] = gen_rtx_MEM (SImode, gen_rtx_PLUS (DImode, stack_pointer_rtx, - GEN_INT (4))); - ") +;; Size of pushxf is 3 (for sub) + 2 (for fstp) + memory operand size. +;; Size of pushxf using integer instructions is 3+3*memory operand size +;; Pushing using integer instructions is longer except for constants +;; and direct memory references (assuming that any given constant is pushed +;; only once, but this ought to be handled elsewhere). -(define_insn "*pushdi2_prologue_rex64" - [(set (match_operand:DI 0 "push_operand" "=<") - (match_operand:DI 1 "general_no_elim_operand" "re*m")) - (clobber (mem:BLK (scratch)))] - "TARGET_64BIT" - "push{q}\t%1" - [(set_attr "type" "push") - (set_attr "mode" "DI")]) +(define_insn "*pushxf_nointeger" + [(set (match_operand:XF 0 "push_operand" "=X,X,X") + (match_operand:XF 1 "general_no_elim_operand" "f,Fo,*r"))] + "optimize_function_for_size_p (cfun)" +{ + /* This insn should be already split before reg-stack. */ + gcc_unreachable (); +} + [(set_attr "type" "multi") + (set_attr "unit" "i387,*,*") + (set_attr "mode" "XF,SI,SI")]) -(define_insn "*popdi1_epilogue_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r*m") - (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) - (plus:DI (reg:DI SP_REG) (const_int 8))) - (clobber (mem:BLK (scratch)))] - "TARGET_64BIT" - "pop{q}\t%0" - [(set_attr "type" "pop") - (set_attr "mode" "DI")]) +(define_split + [(set (match_operand:XF 0 "push_operand" "") + (match_operand:XF 1 "any_fp_register_operand" ""))] + "reload_completed" + [(set (reg:P SP_REG) (plus:P (reg:P SP_REG) (match_dup 2))) + (set (mem:XF (reg:P SP_REG)) (match_dup 1))] + "operands[2] = GEN_INT (-GET_MODE_SIZE (XFmode));") -(define_insn "popdi1" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r*m") - (mem:DI (reg:DI SP_REG))) - (set (reg:DI SP_REG) - (plus:DI (reg:DI SP_REG) (const_int 8)))] - "TARGET_64BIT" - "pop{q}\t%0" - [(set_attr "type" "pop") - (set_attr "mode" "DI")]) +(define_split + [(set (match_operand:XF 0 "push_operand" "") + (match_operand:XF 1 "general_operand" ""))] + "reload_completed + && !ANY_FP_REG_P (operands[1])" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") -(define_insn "*movdi_xor_rex64" - [(set (match_operand:DI 0 "register_operand" "=r") - (match_operand:DI 1 "const0_operand" "")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && reload_completed" - "xor{l}\t%k0, %k0"; - [(set_attr "type" "alu1") - (set_attr "mode" "SI") - (set_attr "length_immediate" "0")]) +(define_insn "*pushdf" + [(set (match_operand:DF 0 "push_operand" "=<,<,<") + (match_operand:DF 1 "general_no_elim_operand" "f,rFo,Y2"))] + "TARGET_64BIT || TARGET_INTEGER_DFMODE_MOVES" +{ + /* This insn should be already split before reg-stack. */ + gcc_unreachable (); +} + [(set_attr "type" "multi") + (set_attr "unit" "i387,*,*") + (set_attr "mode" "DF,SI,DF")]) -(define_insn "*movdi_or_rex64" - [(set (match_operand:DI 0 "register_operand" "=r") - (match_operand:DI 1 "const_int_operand" "i")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && reload_completed - && operands[1] == constm1_rtx" +;; Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size. +;; Size of pushdf using integer instructions is 2+2*memory operand size +;; On the average, pushdf using integers can be still shorter. Allow this +;; pattern for optimize_size too. + +(define_insn "*pushdf_nointeger" + [(set (match_operand:DF 0 "push_operand" "=<,<,<,<") + (match_operand:DF 1 "general_no_elim_operand" "f,Fo,*r,Y2"))] + "!(TARGET_64BIT || TARGET_INTEGER_DFMODE_MOVES)" { - operands[1] = constm1_rtx; - return "or{q}\t{%1, %0|%0, %1}"; + /* This insn should be already split before reg-stack. */ + gcc_unreachable (); } - [(set_attr "type" "alu1") - (set_attr "mode" "DI") - (set_attr "length_immediate" "1")]) + [(set_attr "type" "multi") + (set_attr "unit" "i387,*,*,*") + (set_attr "mode" "DF,SI,SI,DF")]) -(define_insn "*movdi_2" - [(set (match_operand:DI 0 "nonimmediate_operand" - "=r ,o ,*y,m*y,*y,*Y2,m ,*Y2,*Y2,*x,m ,*x,*x") - (match_operand:DI 1 "general_operand" - "riFo,riF,C ,*y ,m ,C ,*Y2,*Y2,m ,C ,*x,*x,m "))] - "!TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "@ - # - # - pxor\t%0, %0 - movq\t{%1, %0|%0, %1} - movq\t{%1, %0|%0, %1} - %vpxor\t%0, %d0 - %vmovq\t{%1, %0|%0, %1} - %vmovdqa\t{%1, %0|%0, %1} - %vmovq\t{%1, %0|%0, %1} - xorps\t%0, %0 - movlps\t{%1, %0|%0, %1} - movaps\t{%1, %0|%0, %1} - movlps\t{%1, %0|%0, %1}" - [(set_attr "type" "*,*,mmx,mmxmov,mmxmov,sselog1,ssemov,ssemov,ssemov,sselog1,ssemov,ssemov,ssemov") - (set (attr "prefix") - (if_then_else (eq_attr "alternative" "5,6,7,8") - (const_string "vex") - (const_string "orig"))) - (set_attr "mode" "DI,DI,DI,DI,DI,TI,DI,TI,DI,V4SF,V2SF,V4SF,V2SF")]) +;; %%% Kill this when call knows how to work this out. +(define_split + [(set (match_operand:DF 0 "push_operand" "") + (match_operand:DF 1 "any_fp_register_operand" ""))] + "reload_completed" + [(set (reg:P SP_REG) (plus:P (reg:P SP_REG) (const_int -8))) + (set (mem:DF (reg:P SP_REG)) (match_dup 1))] + "") (define_split - [(set (match_operand:DI 0 "push_operand" "") - (match_operand:DI 1 "general_operand" ""))] - "!TARGET_64BIT && reload_completed - && (! MMX_REG_P (operands[1]) && !SSE_REG_P (operands[1]))" + [(set (match_operand:DF 0 "push_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "reload_completed + && !ANY_FP_REG_P (operands[1])" [(const_int 0)] "ix86_split_long_move (operands); DONE;") -;; %%% This multiword shite has got to go. +(define_insn "*pushsf_rex64" + [(set (match_operand:SF 0 "push_operand" "=X,X,X") + (match_operand:SF 1 "nonmemory_no_elim_operand" "f,rF,x"))] + "TARGET_64BIT" +{ + /* Anything else should be already split before reg-stack. */ + gcc_assert (which_alternative == 1); + return "push{q}\t%q1"; +} + [(set_attr "type" "multi,push,multi") + (set_attr "unit" "i387,*,*") + (set_attr "mode" "SF,DI,SF")]) + +(define_insn "*pushsf" + [(set (match_operand:SF 0 "push_operand" "=<,<,<") + (match_operand:SF 1 "general_no_elim_operand" "f,rFm,x"))] + "!TARGET_64BIT" +{ + /* Anything else should be already split before reg-stack. */ + gcc_assert (which_alternative == 1); + return "push{l}\t%1"; +} + [(set_attr "type" "multi,push,multi") + (set_attr "unit" "i387,*,*") + (set_attr "mode" "SF,SI,SF")]) + (define_split - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (match_operand:DI 1 "general_operand" ""))] - "!TARGET_64BIT && reload_completed - && (!MMX_REG_P (operands[0]) && !SSE_REG_P (operands[0])) - && (!MMX_REG_P (operands[1]) && !SSE_REG_P (operands[1]))" - [(const_int 0)] - "ix86_split_long_move (operands); DONE;") + [(set (match_operand:SF 0 "push_operand" "") + (match_operand:SF 1 "memory_operand" ""))] + "reload_completed + && MEM_P (operands[1]) + && (operands[2] = find_constant_src (insn))" + [(set (match_dup 0) + (match_dup 2))]) -(define_insn "*movdi_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" - "=r,r ,r,m ,!m,*y,*y,?r ,m ,?*Ym,?*y,*x,*x,?r ,m,?*Yi,*x,?*x,?*Ym") - (match_operand:DI 1 "general_operand" - "Z ,rem,i,re,n ,C ,*y,*Ym,*y,r ,m ,C ,*x,*Yi,*x,r ,m ,*Ym,*x"))] - "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))" +;; %%% Kill this when call knows how to work this out. +(define_split + [(set (match_operand:SF 0 "push_operand" "") + (match_operand:SF 1 "any_fp_register_operand" ""))] + "reload_completed" + [(set (reg:P SP_REG) (plus:P (reg:P SP_REG) (match_dup 2))) + (set (mem:SF (reg:P SP_REG)) (match_dup 1))] + "operands[2] = GEN_INT (-GET_MODE_SIZE (mode));") + +(define_insn "*movtf_internal" + [(set (match_operand:TF 0 "nonimmediate_operand" "=x,m,x,?r,?o") + (match_operand:TF 1 "general_operand" "xm,x,C,roF,Fr"))] + "TARGET_SSE2 + && !(MEM_P (operands[0]) && MEM_P (operands[1]))" { - switch (get_attr_type (insn)) + switch (which_alternative) { - case TYPE_SSECVT: - if (SSE_REG_P (operands[0])) - return "movq2dq\t{%1, %0|%0, %1}"; + case 0: + case 1: + if (get_attr_mode (insn) == MODE_V4SF) + return "%vmovaps\t{%1, %0|%0, %1}"; else - return "movdq2q\t{%1, %0|%0, %1}"; - - case TYPE_SSEMOV: - if (TARGET_AVX) - { - if (get_attr_mode (insn) == MODE_TI) - return "vmovdqa\t{%1, %0|%0, %1}"; - else - return "vmovq\t{%1, %0|%0, %1}"; - } - - if (get_attr_mode (insn) == MODE_TI) - return "movdqa\t{%1, %0|%0, %1}"; - /* FALLTHRU */ + return "%vmovdqa\t{%1, %0|%0, %1}"; + case 2: + if (get_attr_mode (insn) == MODE_V4SF) + return "%vxorps\t%0, %d0"; + else + return "%vpxor\t%0, %d0"; + case 3: + case 4: + return "#"; + default: + gcc_unreachable (); + } +} + [(set_attr "type" "ssemov,ssemov,sselog1,*,*") + (set_attr "prefix" "maybe_vex,maybe_vex,maybe_vex,*,*") + (set (attr "mode") + (cond [(eq_attr "alternative" "0,2") + (if_then_else + (ne (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0)) + (const_string "V4SF") + (const_string "TI")) + (eq_attr "alternative" "1") + (if_then_else + (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") + (const_int 0)) + (ne (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "V4SF") + (const_string "TI"))] + (const_string "DI")))]) - case TYPE_MMXMOV: - /* Moves from and into integer register is done using movd - opcode with REX prefix. */ - if (GENERAL_REG_P (operands[0]) || GENERAL_REG_P (operands[1])) - return "movd\t{%1, %0|%0, %1}"; - return "movq\t{%1, %0|%0, %1}"; +(define_split + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (match_operand:TF 1 "general_operand" ""))] + "reload_completed + && !(SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]))" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") - case TYPE_SSELOG1: - return "%vpxor\t%0, %d0"; +(define_insn "*movxf_internal" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,r,o") + (match_operand:XF 1 "general_operand" "fm,f,G,roF,Fr"))] + "optimize_function_for_speed_p (cfun) + && !(MEM_P (operands[0]) && MEM_P (operands[1])) + && (reload_in_progress || reload_completed + || GET_CODE (operands[1]) != CONST_DOUBLE + || memory_operand (operands[0], XFmode))" +{ + switch (which_alternative) + { + case 0: + case 1: + return output_387_reg_move (insn, operands); - case TYPE_MMX: - return "pxor\t%0, %0"; + case 2: + return standard_80387_constant_opcode (operands[1]); - case TYPE_MULTI: + case 3: case 4: return "#"; - case TYPE_LEA: - return "lea{q}\t{%a1, %0|%0, %a1}"; - default: - gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1])); - if (get_attr_mode (insn) == MODE_SI) - return "mov{l}\t{%k1, %k0|%k0, %k1}"; - else if (which_alternative == 2) - return "movabs{q}\t{%1, %0|%0, %1}"; - else - return "mov{q}\t{%1, %0|%0, %1}"; + gcc_unreachable (); } } - [(set (attr "type") - (cond [(eq_attr "alternative" "5") - (const_string "mmx") - (eq_attr "alternative" "6,7,8,9,10") - (const_string "mmxmov") - (eq_attr "alternative" "11") - (const_string "sselog1") - (eq_attr "alternative" "12,13,14,15,16") - (const_string "ssemov") - (eq_attr "alternative" "17,18") - (const_string "ssecvt") - (eq_attr "alternative" "4") - (const_string "multi") - (match_operand:DI 1 "pic_32bit_operand" "") - (const_string "lea") - ] - (const_string "imov"))) - (set (attr "modrm") - (if_then_else - (and (eq_attr "alternative" "2") (eq_attr "type" "imov")) - (const_string "0") - (const_string "*"))) - (set (attr "length_immediate") - (if_then_else - (and (eq_attr "alternative" "2") (eq_attr "type" "imov")) - (const_string "8") - (const_string "*"))) - (set_attr "prefix_rex" "*,*,*,*,*,*,*,1,*,1,*,*,*,*,*,*,*,*,*") - (set_attr "prefix_data16" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,1,*,*,*") - (set (attr "prefix") - (if_then_else (eq_attr "alternative" "11,12,13,14,15,16") - (const_string "maybe_vex") - (const_string "orig"))) - (set_attr "mode" "SI,DI,DI,DI,SI,DI,DI,DI,DI,DI,DI,TI,TI,DI,DI,DI,DI,DI,DI")]) - -;; Stores and loads of ax to arbitrary constant address. -;; We fake an second form of instruction to force reload to load address -;; into register when rax is not available -(define_insn "*movabsdi_1_rex64" - [(set (mem:DI (match_operand:DI 0 "x86_64_movabs_operand" "i,r")) - (match_operand:DI 1 "nonmemory_operand" "a,er"))] - "TARGET_64BIT && ix86_check_movabs (insn, 0)" - "@ - movabs{q}\t{%1, %P0|%P0, %1} - mov{q}\t{%1, %a0|%a0, %1}" - [(set_attr "type" "imov") - (set_attr "modrm" "0,*") - (set_attr "length_address" "8,0") - (set_attr "length_immediate" "0,*") - (set_attr "memory" "store") - (set_attr "mode" "DI")]) - -(define_insn "*movabsdi_2_rex64" - [(set (match_operand:DI 0 "register_operand" "=a,r") - (mem:DI (match_operand:DI 1 "x86_64_movabs_operand" "i,r")))] - "TARGET_64BIT && ix86_check_movabs (insn, 1)" - "@ - movabs{q}\t{%P1, %0|%0, %P1} - mov{q}\t{%a1, %0|%0, %a1}" - [(set_attr "type" "imov") - (set_attr "modrm" "0,*") - (set_attr "length_address" "8,0") - (set_attr "length_immediate" "0") - (set_attr "memory" "load") - (set_attr "mode" "DI")]) - -;; Convert impossible stores of immediate to existing instructions. -;; First try to get scratch register and go through it. In case this -;; fails, move by 32bit parts. -(define_peephole2 - [(match_scratch:DI 2 "r") - (set (match_operand:DI 0 "memory_operand" "") - (match_operand:DI 1 "immediate_operand" ""))] - "TARGET_64BIT && !symbolic_operand (operands[1], DImode) - && !x86_64_immediate_operand (operands[1], DImode)" - [(set (match_dup 2) (match_dup 1)) - (set (match_dup 0) (match_dup 2))] - "") - -;; We need to define this as both peepholer and splitter for case -;; peephole2 pass is not run. -;; "&& 1" is needed to keep it from matching the previous pattern. -(define_peephole2 - [(set (match_operand:DI 0 "memory_operand" "") - (match_operand:DI 1 "immediate_operand" ""))] - "TARGET_64BIT && !symbolic_operand (operands[1], DImode) - && !x86_64_immediate_operand (operands[1], DImode) && 1" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 4) (match_dup 5))] - "split_di (&operands[0], 2, &operands[2], &operands[4]);") - -(define_split - [(set (match_operand:DI 0 "memory_operand" "") - (match_operand:DI 1 "immediate_operand" ""))] - "TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? epilogue_completed : reload_completed) - && !symbolic_operand (operands[1], DImode) - && !x86_64_immediate_operand (operands[1], DImode)" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 4) (match_dup 5))] - "split_di (&operands[0], 2, &operands[2], &operands[4]);") - -(define_insn "*swapdi_rex64" - [(set (match_operand:DI 0 "register_operand" "+r") - (match_operand:DI 1 "register_operand" "+r")) - (set (match_dup 1) - (match_dup 0))] - "TARGET_64BIT" - "xchg{q}\t%1, %0" - [(set_attr "type" "imov") - (set_attr "mode" "DI") - (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector") - (set_attr "amdfam10_decode" "double")]) - -(define_expand "movoi" - [(set (match_operand:OI 0 "nonimmediate_operand" "") - (match_operand:OI 1 "general_operand" ""))] - "TARGET_AVX" - "ix86_expand_move (OImode, operands); DONE;") + [(set_attr "type" "fmov,fmov,fmov,multi,multi") + (set_attr "mode" "XF,XF,XF,SI,SI")]) -(define_insn "*movoi_internal" - [(set (match_operand:OI 0 "nonimmediate_operand" "=x,x,m") - (match_operand:OI 1 "vector_move_operand" "C,xm,x"))] - "TARGET_AVX - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" +;; Do not use integer registers when optimizing for size +(define_insn "*movxf_internal_nointeger" + [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,*r,o") + (match_operand:XF 1 "general_operand" "fm,f,G,*roF,F*r"))] + "optimize_function_for_size_p (cfun) + && !(MEM_P (operands[0]) && MEM_P (operands[1])) + && (reload_in_progress || reload_completed + || standard_80387_constant_p (operands[1]) + || GET_CODE (operands[1]) != CONST_DOUBLE + || memory_operand (operands[0], XFmode))" { switch (which_alternative) { case 0: - return "vxorps\t%0, %0, %0"; case 1: + return output_387_reg_move (insn, operands); + case 2: - if (misaligned_operand (operands[0], OImode) - || misaligned_operand (operands[1], OImode)) - return "vmovdqu\t{%1, %0|%0, %1}"; - else - return "vmovdqa\t{%1, %0|%0, %1}"; + return standard_80387_constant_opcode (operands[1]); + + case 3: case 4: + return "#"; default: gcc_unreachable (); } } - [(set_attr "type" "sselog1,ssemov,ssemov") - (set_attr "prefix" "vex") - (set_attr "mode" "OI")]) + [(set_attr "type" "fmov,fmov,fmov,multi,multi") + (set_attr "mode" "XF,XF,XF,SI,SI")]) -(define_expand "movti" - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (match_operand:TI 1 "nonimmediate_operand" ""))] - "TARGET_SSE || TARGET_64BIT" -{ - if (TARGET_64BIT) - ix86_expand_move (TImode, operands); - else if (push_operand (operands[0], TImode)) - ix86_expand_push (TImode, operands[1]); - else - ix86_expand_vector_move (TImode, operands); - DONE; -}) +(define_split + [(set (match_operand:XF 0 "nonimmediate_operand" "") + (match_operand:XF 1 "general_operand" ""))] + "reload_completed + && !(MEM_P (operands[0]) && MEM_P (operands[1])) + && ! (ANY_FP_REG_P (operands[0]) || + (GET_CODE (operands[0]) == SUBREG + && ANY_FP_REG_P (SUBREG_REG (operands[0])))) + && ! (ANY_FP_REG_P (operands[1]) || + (GET_CODE (operands[1]) == SUBREG + && ANY_FP_REG_P (SUBREG_REG (operands[1]))))" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") -(define_insn "*movti_internal" - [(set (match_operand:TI 0 "nonimmediate_operand" "=x,x,m") - (match_operand:TI 1 "vector_move_operand" "C,xm,x"))] - "TARGET_SSE && !TARGET_64BIT - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" +(define_insn "*movdf_internal_rex64" + [(set (match_operand:DF 0 "nonimmediate_operand" + "=f,m,f,r ,m ,Y2*x,Y2*x,Y2*x,m ,Yi,r ") + (match_operand:DF 1 "general_operand" + "fm,f,G,rmF,Fr,C ,Y2*x,m ,Y2*x,r ,Yi"))] + "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1])) + && (reload_in_progress || reload_completed + || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) + || (!(TARGET_SSE2 && TARGET_SSE_MATH) + && optimize_function_for_size_p (cfun) + && standard_80387_constant_p (operands[1])) + || GET_CODE (operands[1]) != CONST_DOUBLE + || memory_operand (operands[0], DFmode))" { switch (which_alternative) { case 0: - if (get_attr_mode (insn) == MODE_V4SF) - return "%vxorps\t%0, %d0"; - else - return "%vpxor\t%0, %d0"; case 1: + return output_387_reg_move (insn, operands); + case 2: - /* TDmode values are passed as TImode on the stack. Moving them - to stack may result in unaligned memory access. */ - if (misaligned_operand (operands[0], TImode) - || misaligned_operand (operands[1], TImode)) + return standard_80387_constant_opcode (operands[1]); + + case 3: + case 4: + return "#"; + + case 5: + switch (get_attr_mode (insn)) { - if (get_attr_mode (insn) == MODE_V4SF) - return "%vmovups\t{%1, %0|%0, %1}"; - else - return "%vmovdqu\t{%1, %0|%0, %1}"; + case MODE_V4SF: + return "%vxorps\t%0, %d0"; + case MODE_V2DF: + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) + return "%vxorps\t%0, %d0"; + else + return "%vxorpd\t%0, %d0"; + case MODE_TI: + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) + return "%vxorps\t%0, %d0"; + else + return "%vpxor\t%0, %d0"; + default: + gcc_unreachable (); } - else + case 6: + case 7: + case 8: + switch (get_attr_mode (insn)) { - if (get_attr_mode (insn) == MODE_V4SF) + case MODE_V4SF: + return "%vmovaps\t{%1, %0|%0, %1}"; + case MODE_V2DF: + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) return "%vmovaps\t{%1, %0|%0, %1}"; - else - return "%vmovdqa\t{%1, %0|%0, %1}"; + else + return "%vmovapd\t{%1, %0|%0, %1}"; + case MODE_TI: + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) + return "%vmovaps\t{%1, %0|%0, %1}"; + else + return "%vmovdqa\t{%1, %0|%0, %1}"; + case MODE_DI: + return "%vmovq\t{%1, %0|%0, %1}"; + case MODE_DF: + if (TARGET_AVX) + { + if (REG_P (operands[0]) && REG_P (operands[1])) + return "vmovsd\t{%1, %0, %0|%0, %0, %1}"; + else + return "vmovsd\t{%1, %0|%0, %1}"; + } + else + return "movsd\t{%1, %0|%0, %1}"; + case MODE_V1DF: + return "%vmovlpd\t{%1, %d0|%d0, %1}"; + case MODE_V2SF: + return "%vmovlps\t{%1, %d0|%d0, %1}"; + default: + gcc_unreachable (); } + + case 9: + case 10: + return "%vmovd\t{%1, %0|%0, %1}"; + default: - gcc_unreachable (); + gcc_unreachable(); } } - [(set_attr "type" "sselog1,ssemov,ssemov") - (set_attr "prefix" "maybe_vex") + [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov,ssemov,ssemov") + (set (attr "prefix") + (if_then_else (eq_attr "alternative" "0,1,2,3,4") + (const_string "orig") + (const_string "maybe_vex"))) + (set (attr "prefix_data16") + (if_then_else (eq_attr "mode" "V1DF") + (const_string "1") + (const_string "*"))) (set (attr "mode") - (cond [(ior (eq (symbol_ref "TARGET_SSE2") (const_int 0)) - (ne (symbol_ref "optimize_function_for_size_p (cfun)") (const_int 0))) - (const_string "V4SF") - (and (eq_attr "alternative" "2") - (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") - (const_int 0))) - (const_string "V4SF")] - (const_string "TI")))]) - -(define_insn "*movti_rex64" - [(set (match_operand:TI 0 "nonimmediate_operand" "=!r,o,x,x,xm") - (match_operand:TI 1 "general_operand" "riFo,riF,C,xm,x"))] - "TARGET_64BIT - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" -{ - switch (which_alternative) - { - case 0: - case 1: - return "#"; - case 2: - if (get_attr_mode (insn) == MODE_V4SF) - return "%vxorps\t%0, %d0"; - else - return "%vpxor\t%0, %d0"; - case 3: - case 4: - /* TDmode values are passed as TImode on the stack. Moving them - to stack may result in unaligned memory access. */ - if (misaligned_operand (operands[0], TImode) - || misaligned_operand (operands[1], TImode)) - { - if (get_attr_mode (insn) == MODE_V4SF) - return "%vmovups\t{%1, %0|%0, %1}"; - else - return "%vmovdqu\t{%1, %0|%0, %1}"; - } - else - { - if (get_attr_mode (insn) == MODE_V4SF) - return "%vmovaps\t{%1, %0|%0, %1}"; - else - return "%vmovdqa\t{%1, %0|%0, %1}"; - } - default: - gcc_unreachable (); - } -} - [(set_attr "type" "*,*,sselog1,ssemov,ssemov") - (set_attr "prefix" "*,*,maybe_vex,maybe_vex,maybe_vex") - (set (attr "mode") - (cond [(eq_attr "alternative" "2,3") - (if_then_else - (ne (symbol_ref "optimize_function_for_size_p (cfun)") - (const_int 0)) - (const_string "V4SF") - (const_string "TI")) - (eq_attr "alternative" "4") - (if_then_else - (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") - (const_int 0)) - (ne (symbol_ref "optimize_function_for_size_p (cfun)") - (const_int 0))) - (const_string "V4SF") - (const_string "TI"))] - (const_string "DI")))]) - -(define_split - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (match_operand:TI 1 "general_operand" ""))] - "reload_completed && !SSE_REG_P (operands[0]) - && !SSE_REG_P (operands[1])" - [(const_int 0)] - "ix86_split_long_move (operands); DONE;") - -;; This expands to what emit_move_complex would generate if we didn't -;; have a movti pattern. Having this avoids problems with reload on -;; 32-bit targets when SSE is present, but doesn't seem to be harmful -;; to have around all the time. -(define_expand "movcdi" - [(set (match_operand:CDI 0 "nonimmediate_operand" "") - (match_operand:CDI 1 "general_operand" ""))] - "" -{ - if (push_operand (operands[0], CDImode)) - emit_move_complex_push (CDImode, operands[0], operands[1]); - else - emit_move_complex_parts (operands[0], operands[1]); - DONE; -}) - -(define_expand "movsf" - [(set (match_operand:SF 0 "nonimmediate_operand" "") - (match_operand:SF 1 "general_operand" ""))] - "" - "ix86_expand_move (SFmode, operands); DONE;") - -(define_insn "*pushsf" - [(set (match_operand:SF 0 "push_operand" "=<,<,<") - (match_operand:SF 1 "general_no_elim_operand" "f,rFm,x"))] - "!TARGET_64BIT" -{ - /* Anything else should be already split before reg-stack. */ - gcc_assert (which_alternative == 1); - return "push{l}\t%1"; -} - [(set_attr "type" "multi,push,multi") - (set_attr "unit" "i387,*,*") - (set_attr "mode" "SF,SI,SF")]) + (cond [(eq_attr "alternative" "0,1,2") + (const_string "DF") + (eq_attr "alternative" "3,4,9,10") + (const_string "DI") -(define_insn "*pushsf_rex64" - [(set (match_operand:SF 0 "push_operand" "=X,X,X") - (match_operand:SF 1 "nonmemory_no_elim_operand" "f,rF,x"))] - "TARGET_64BIT" -{ - /* Anything else should be already split before reg-stack. */ - gcc_assert (which_alternative == 1); - return "push{q}\t%q1"; -} - [(set_attr "type" "multi,push,multi") - (set_attr "unit" "i387,*,*") - (set_attr "mode" "SF,DI,SF")]) + /* For SSE1, we have many fewer alternatives. */ + (eq (symbol_ref "TARGET_SSE2") (const_int 0)) + (cond [(eq_attr "alternative" "5,6") + (const_string "V4SF") + ] + (const_string "V2SF")) -(define_split - [(set (match_operand:SF 0 "push_operand" "") - (match_operand:SF 1 "memory_operand" ""))] - "reload_completed - && MEM_P (operands[1]) - && (operands[2] = find_constant_src (insn))" - [(set (match_dup 0) - (match_dup 2))]) + /* xorps is one byte shorter. */ + (eq_attr "alternative" "5") + (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0)) + (const_string "V4SF") + (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") + (const_int 0)) + (const_string "TI") + ] + (const_string "V2DF")) -;; %%% Kill this when call knows how to work this out. -(define_split - [(set (match_operand:SF 0 "push_operand" "") - (match_operand:SF 1 "any_fp_register_operand" ""))] - "!TARGET_64BIT" - [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -4))) - (set (mem:SF (reg:SI SP_REG)) (match_dup 1))]) + /* For architectures resolving dependencies on + whole SSE registers use APD move to break dependency + chains, otherwise use short move to avoid extra work. -(define_split - [(set (match_operand:SF 0 "push_operand" "") - (match_operand:SF 1 "any_fp_register_operand" ""))] - "TARGET_64BIT" - [(set (reg:DI SP_REG) (plus:DI (reg:DI SP_REG) (const_int -8))) - (set (mem:SF (reg:DI SP_REG)) (match_dup 1))]) + movaps encodes one byte shorter. */ + (eq_attr "alternative" "6") + (cond + [(ne (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0)) + (const_string "V4SF") + (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") + (const_int 0)) + (const_string "V2DF") + ] + (const_string "DF")) + /* For architectures resolving dependencies on register + parts we may avoid extra work to zero out upper part + of register. */ + (eq_attr "alternative" "7") + (if_then_else + (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") + (const_int 0)) + (const_string "V1DF") + (const_string "DF")) + ] + (const_string "DF")))]) -(define_insn "*movsf_1" - [(set (match_operand:SF 0 "nonimmediate_operand" - "=f,m,f,r ,m ,x,x,x ,m,!*y,!m,!*y,?Yi,?r,!*Ym,!r") - (match_operand:SF 1 "general_operand" - "fm,f,G,rmF,Fr,C,x,xm,x,m ,*y,*y ,r ,Yi,r ,*Ym"))] +(define_insn "*movdf_internal" + [(set (match_operand:DF 0 "nonimmediate_operand" + "=f,m,f,r ,o ,Y2*x,Y2*x,Y2*x,m ") + (match_operand:DF 1 "general_operand" + "fm,f,G,roF,Fr,C ,Y2*x,m ,Y2*x"))] "!(MEM_P (operands[0]) && MEM_P (operands[1])) + && optimize_function_for_speed_p (cfun) + && TARGET_INTEGER_DFMODE_MOVES && (reload_in_progress || reload_completed || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) - || (!TARGET_SSE_MATH && optimize_function_for_size_p (cfun) + || (!(TARGET_SSE2 && TARGET_SSE_MATH) + && optimize_function_for_size_p (cfun) && standard_80387_constant_p (operands[1])) || GET_CODE (operands[1]) != CONST_DOUBLE - || memory_operand (operands[0], SFmode))" + || memory_operand (operands[0], DFmode))" { switch (which_alternative) { @@ -3079,149 +3097,120 @@ case 3: case 4: - return "mov{l}\t{%1, %0|%0, %1}"; + return "#"; + case 5: - if (get_attr_mode (insn) == MODE_TI) - return "%vpxor\t%0, %d0"; - else - return "%vxorps\t%0, %d0"; + switch (get_attr_mode (insn)) + { + case MODE_V4SF: + return "xorps\t%0, %0"; + case MODE_V2DF: + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) + return "xorps\t%0, %0"; + else + return "xorpd\t%0, %0"; + case MODE_TI: + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) + return "xorps\t%0, %0"; + else + return "pxor\t%0, %0"; + default: + gcc_unreachable (); + } case 6: - if (get_attr_mode (insn) == MODE_V4SF) - return "%vmovaps\t{%1, %0|%0, %1}"; - else - return "%vmovss\t{%1, %d0|%d0, %1}"; case 7: - if (TARGET_AVX) - return REG_P (operands[1]) ? "vmovss\t{%1, %0, %0|%0, %0, %1}" - : "vmovss\t{%1, %0|%0, %1}"; - else - return "movss\t{%1, %0|%0, %1}"; case 8: - return "%vmovss\t{%1, %0|%0, %1}"; - - case 9: case 10: case 14: case 15: - return "movd\t{%1, %0|%0, %1}"; - case 12: case 13: - return "%vmovd\t{%1, %0|%0, %1}"; - - case 11: - return "movq\t{%1, %0|%0, %1}"; + switch (get_attr_mode (insn)) + { + case MODE_V4SF: + return "movaps\t{%1, %0|%0, %1}"; + case MODE_V2DF: + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movapd\t{%1, %0|%0, %1}"; + case MODE_TI: + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) + return "movaps\t{%1, %0|%0, %1}"; + else + return "movdqa\t{%1, %0|%0, %1}"; + case MODE_DI: + return "movq\t{%1, %0|%0, %1}"; + case MODE_DF: + return "movsd\t{%1, %0|%0, %1}"; + case MODE_V1DF: + return "movlpd\t{%1, %0|%0, %1}"; + case MODE_V2SF: + return "movlps\t{%1, %0|%0, %1}"; + default: + gcc_unreachable (); + } default: - gcc_unreachable (); + gcc_unreachable(); } } - [(set_attr "type" "fmov,fmov,fmov,imov,imov,sselog1,ssemov,ssemov,ssemov,mmxmov,mmxmov,mmxmov,ssemov,ssemov,mmxmov,mmxmov") - (set (attr "prefix") - (if_then_else (eq_attr "alternative" "5,6,7,8,12,13") - (const_string "maybe_vex") - (const_string "orig"))) + [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov") + (set (attr "prefix_data16") + (if_then_else (eq_attr "mode" "V1DF") + (const_string "1") + (const_string "*"))) (set (attr "mode") - (cond [(eq_attr "alternative" "3,4,9,10") + (cond [(eq_attr "alternative" "0,1,2") + (const_string "DF") + (eq_attr "alternative" "3,4") (const_string "SI") - (eq_attr "alternative" "5") - (if_then_else - (and (and (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") - (const_int 0)) - (ne (symbol_ref "TARGET_SSE2") - (const_int 0))) - (eq (symbol_ref "optimize_function_for_size_p (cfun)") - (const_int 0))) - (const_string "TI") - (const_string "V4SF")) + + /* For SSE1, we have many fewer alternatives. */ + (eq (symbol_ref "TARGET_SSE2") (const_int 0)) + (cond [(eq_attr "alternative" "5,6") + (const_string "V4SF") + ] + (const_string "V2SF")) + + /* xorps is one byte shorter. */ + (eq_attr "alternative" "5") + (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0)) + (const_string "V4SF") + (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") + (const_int 0)) + (const_string "TI") + ] + (const_string "V2DF")) + /* For architectures resolving dependencies on - whole SSE registers use APS move to break dependency + whole SSE registers use APD move to break dependency chains, otherwise use short move to avoid extra work. - Do the same for architectures resolving dependencies on - the parts. While in DF mode it is better to always handle - just register parts, the SF mode is different due to lack - of instructions to load just part of the register. It is - better to maintain the whole registers in single format - to avoid problems on using packed logical operations. */ + movaps encodes one byte shorter. */ (eq_attr "alternative" "6") + (cond + [(ne (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0)) + (const_string "V4SF") + (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") + (const_int 0)) + (const_string "V2DF") + ] + (const_string "DF")) + /* For architectures resolving dependencies on register + parts we may avoid extra work to zero out upper part + of register. */ + (eq_attr "alternative" "7") (if_then_else - (ior (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") - (const_int 0)) - (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") - (const_int 0))) - (const_string "V4SF") - (const_string "SF")) - (eq_attr "alternative" "11") - (const_string "DI")] - (const_string "SF")))]) - -(define_insn "*swapsf" - [(set (match_operand:SF 0 "fp_register_operand" "+f") - (match_operand:SF 1 "fp_register_operand" "+f")) - (set (match_dup 1) - (match_dup 0))] - "reload_completed || TARGET_80387" -{ - if (STACK_TOP_P (operands[0])) - return "fxch\t%1"; - else - return "fxch\t%0"; -} - [(set_attr "type" "fxch") - (set_attr "mode" "SF")]) - -(define_expand "movdf" - [(set (match_operand:DF 0 "nonimmediate_operand" "") - (match_operand:DF 1 "general_operand" ""))] - "" - "ix86_expand_move (DFmode, operands); DONE;") - -;; Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size. -;; Size of pushdf using integer instructions is 2+2*memory operand size -;; On the average, pushdf using integers can be still shorter. Allow this -;; pattern for optimize_size too. - -(define_insn "*pushdf_nointeger" - [(set (match_operand:DF 0 "push_operand" "=<,<,<,<") - (match_operand:DF 1 "general_no_elim_operand" "f,Fo,*r,Y2"))] - "!TARGET_64BIT && !TARGET_INTEGER_DFMODE_MOVES" -{ - /* This insn should be already split before reg-stack. */ - gcc_unreachable (); -} - [(set_attr "type" "multi") - (set_attr "unit" "i387,*,*,*") - (set_attr "mode" "DF,SI,SI,DF")]) - -(define_insn "*pushdf_integer" - [(set (match_operand:DF 0 "push_operand" "=<,<,<") - (match_operand:DF 1 "general_no_elim_operand" "f,rFo,Y2"))] - "TARGET_64BIT || TARGET_INTEGER_DFMODE_MOVES" -{ - /* This insn should be already split before reg-stack. */ - gcc_unreachable (); -} - [(set_attr "type" "multi") - (set_attr "unit" "i387,*,*") - (set_attr "mode" "DF,SI,DF")]) - -;; %%% Kill this when call knows how to work this out. -(define_split - [(set (match_operand:DF 0 "push_operand" "") - (match_operand:DF 1 "any_fp_register_operand" ""))] - "reload_completed" - [(set (reg:P SP_REG) (plus:P (reg:P SP_REG) (const_int -8))) - (set (mem:DF (reg:P SP_REG)) (match_dup 1))] - "") - -(define_split - [(set (match_operand:DF 0 "push_operand" "") - (match_operand:DF 1 "general_operand" ""))] - "reload_completed" - [(const_int 0)] - "ix86_split_long_move (operands); DONE;") + (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") + (const_int 0)) + (const_string "V1DF") + (const_string "DF")) + ] + (const_string "DF")))]) ;; Moving is usually shorter when only FP registers are used. This separate ;; movdf pattern avoids the use of integer registers for FP operations ;; when optimizing for size. -(define_insn "*movdf_nointeger" +(define_insn "*movdf_internal_nointeger" [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,f,*r ,o ,Y2*x,Y2*x,Y2*x ,m ") (match_operand:DF 1 "general_operand" @@ -3259,9 +3248,15 @@ case MODE_V4SF: return "%vxorps\t%0, %d0"; case MODE_V2DF: - return "%vxorpd\t%0, %d0"; + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) + return "%vxorps\t%0, %d0"; + else + return "%vxorpd\t%0, %d0"; case MODE_TI: - return "%vpxor\t%0, %d0"; + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) + return "%vxorps\t%0, %d0"; + else + return "%vpxor\t%0, %d0"; default: gcc_unreachable (); } @@ -3273,9 +3268,15 @@ case MODE_V4SF: return "%vmovaps\t{%1, %0|%0, %1}"; case MODE_V2DF: - return "%vmovapd\t{%1, %0|%0, %1}"; + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) + return "%vmovaps\t{%1, %0|%0, %1}"; + else + return "%vmovapd\t{%1, %0|%0, %1}"; case MODE_TI: - return "%vmovdqa\t{%1, %0|%0, %1}"; + if (TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL) + return "%vmovaps\t{%1, %0|%0, %1}"; + else + return "%vmovdqa\t{%1, %0|%0, %1}"; case MODE_DI: return "%vmovq\t{%1, %0|%0, %1}"; case MODE_DF: @@ -3376,19 +3377,32 @@ ] (const_string "DF")))]) -(define_insn "*movdf_integer_rex64" - [(set (match_operand:DF 0 "nonimmediate_operand" - "=f,m,f,r ,m ,Y2*x,Y2*x,Y2*x,m ,Yi,r ") - (match_operand:DF 1 "general_operand" - "fm,f,G,rmF,Fr,C ,Y2*x,m ,Y2*x,r ,Yi"))] - "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1])) +(define_split + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "reload_completed + && !(MEM_P (operands[0]) && MEM_P (operands[1])) + && ! (ANY_FP_REG_P (operands[0]) || + (GET_CODE (operands[0]) == SUBREG + && ANY_FP_REG_P (SUBREG_REG (operands[0])))) + && ! (ANY_FP_REG_P (operands[1]) || + (GET_CODE (operands[1]) == SUBREG + && ANY_FP_REG_P (SUBREG_REG (operands[1]))))" + [(const_int 0)] + "ix86_split_long_move (operands); DONE;") + +(define_insn "*movsf_internal" + [(set (match_operand:SF 0 "nonimmediate_operand" + "=f,m,f,r ,m ,x,x,x ,m,!*y,!m,!*y,?Yi,?r,!*Ym,!r") + (match_operand:SF 1 "general_operand" + "fm,f,G,rmF,Fr,C,x,xm,x,m ,*y,*y ,r ,Yi,r ,*Ym"))] + "!(MEM_P (operands[0]) && MEM_P (operands[1])) && (reload_in_progress || reload_completed || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) - || (!(TARGET_SSE2 && TARGET_SSE_MATH) - && optimize_function_for_size_p (cfun) + || (!TARGET_SSE_MATH && optimize_function_for_size_p (cfun) && standard_80387_constant_p (operands[1])) || GET_CODE (operands[1]) != CONST_DOUBLE - || memory_operand (operands[0], DFmode))" + || memory_operand (operands[0], SFmode))" { switch (which_alternative) { @@ -3401,263 +3415,168 @@ case 3: case 4: - return "#"; - + return "mov{l}\t{%1, %0|%0, %1}"; case 5: - switch (get_attr_mode (insn)) - { - case MODE_V4SF: - return "%vxorps\t%0, %d0"; - case MODE_V2DF: - return "%vxorpd\t%0, %d0"; - case MODE_TI: - return "%vpxor\t%0, %d0"; - default: - gcc_unreachable (); - } + if (get_attr_mode (insn) == MODE_TI) + return "%vpxor\t%0, %d0"; + else + return "%vxorps\t%0, %d0"; case 6: + if (get_attr_mode (insn) == MODE_V4SF) + return "%vmovaps\t{%1, %0|%0, %1}"; + else + return "%vmovss\t{%1, %d0|%d0, %1}"; case 7: + if (TARGET_AVX) + return REG_P (operands[1]) ? "vmovss\t{%1, %0, %0|%0, %0, %1}" + : "vmovss\t{%1, %0|%0, %1}"; + else + return "movss\t{%1, %0|%0, %1}"; case 8: - switch (get_attr_mode (insn)) - { - case MODE_V4SF: - return "%vmovaps\t{%1, %0|%0, %1}"; - case MODE_V2DF: - return "%vmovapd\t{%1, %0|%0, %1}"; - case MODE_TI: - return "%vmovdqa\t{%1, %0|%0, %1}"; - case MODE_DI: - return "%vmovq\t{%1, %0|%0, %1}"; - case MODE_DF: - if (TARGET_AVX) - { - if (REG_P (operands[0]) && REG_P (operands[1])) - return "vmovsd\t{%1, %0, %0|%0, %0, %1}"; - else - return "vmovsd\t{%1, %0|%0, %1}"; - } - else - return "movsd\t{%1, %0|%0, %1}"; - case MODE_V1DF: - return "%vmovlpd\t{%1, %d0|%d0, %1}"; - case MODE_V2SF: - return "%vmovlps\t{%1, %d0|%d0, %1}"; - default: - gcc_unreachable (); - } + return "%vmovss\t{%1, %0|%0, %1}"; - case 9: - case 10: - return "%vmovd\t{%1, %0|%0, %1}"; + case 9: case 10: case 14: case 15: + return "movd\t{%1, %0|%0, %1}"; + case 12: case 13: + return "%vmovd\t{%1, %0|%0, %1}"; + + case 11: + return "movq\t{%1, %0|%0, %1}"; default: - gcc_unreachable(); + gcc_unreachable (); } } - [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov,ssemov,ssemov") + [(set_attr "type" "fmov,fmov,fmov,imov,imov,sselog1,ssemov,ssemov,ssemov,mmxmov,mmxmov,mmxmov,ssemov,ssemov,mmxmov,mmxmov") (set (attr "prefix") - (if_then_else (eq_attr "alternative" "0,1,2,3,4") - (const_string "orig") - (const_string "maybe_vex"))) - (set (attr "prefix_data16") - (if_then_else (eq_attr "mode" "V1DF") - (const_string "1") - (const_string "*"))) + (if_then_else (eq_attr "alternative" "5,6,7,8,12,13") + (const_string "maybe_vex") + (const_string "orig"))) (set (attr "mode") - (cond [(eq_attr "alternative" "0,1,2") - (const_string "DF") - (eq_attr "alternative" "3,4,9,10") - (const_string "DI") - - /* For SSE1, we have many fewer alternatives. */ - (eq (symbol_ref "TARGET_SSE2") (const_int 0)) - (cond [(eq_attr "alternative" "5,6") - (const_string "V4SF") - ] - (const_string "V2SF")) - - /* xorps is one byte shorter. */ + (cond [(eq_attr "alternative" "3,4,9,10") + (const_string "SI") (eq_attr "alternative" "5") - (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") - (const_int 0)) - (const_string "V4SF") - (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") - (const_int 0)) - (const_string "TI") - ] - (const_string "V2DF")) - + (if_then_else + (and (and (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") + (const_int 0)) + (ne (symbol_ref "TARGET_SSE2") + (const_int 0))) + (eq (symbol_ref "optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "TI") + (const_string "V4SF")) /* For architectures resolving dependencies on - whole SSE registers use APD move to break dependency + whole SSE registers use APS move to break dependency chains, otherwise use short move to avoid extra work. - movaps encodes one byte shorter. */ + Do the same for architectures resolving dependencies on + the parts. While in DF mode it is better to always handle + just register parts, the SF mode is different due to lack + of instructions to load just part of the register. It is + better to maintain the whole registers in single format + to avoid problems on using packed logical operations. */ (eq_attr "alternative" "6") - (cond - [(ne (symbol_ref "optimize_function_for_size_p (cfun)") - (const_int 0)) - (const_string "V4SF") - (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") - (const_int 0)) - (const_string "V2DF") - ] - (const_string "DF")) - /* For architectures resolving dependencies on register - parts we may avoid extra work to zero out upper part - of register. */ - (eq_attr "alternative" "7") (if_then_else - (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") - (const_int 0)) - (const_string "V1DF") - (const_string "DF")) - ] - (const_string "DF")))]) + (ior (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") + (const_int 0)) + (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") + (const_int 0))) + (const_string "V4SF") + (const_string "SF")) + (eq_attr "alternative" "11") + (const_string "DI")] + (const_string "SF")))]) -(define_insn "*movdf_integer" - [(set (match_operand:DF 0 "nonimmediate_operand" - "=f,m,f,r ,o ,Y2*x,Y2*x,Y2*x,m ") - (match_operand:DF 1 "general_operand" - "fm,f,G,roF,Fr,C ,Y2*x,m ,Y2*x"))] - "!(MEM_P (operands[0]) && MEM_P (operands[1])) - && optimize_function_for_speed_p (cfun) - && TARGET_INTEGER_DFMODE_MOVES - && (reload_in_progress || reload_completed - || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE) - || (!(TARGET_SSE2 && TARGET_SSE_MATH) - && optimize_function_for_size_p (cfun) - && standard_80387_constant_p (operands[1])) - || GET_CODE (operands[1]) != CONST_DOUBLE - || memory_operand (operands[0], DFmode))" +(define_split + [(set (match_operand 0 "register_operand" "") + (match_operand 1 "memory_operand" ""))] + "reload_completed + && MEM_P (operands[1]) + && (GET_MODE (operands[0]) == TFmode + || GET_MODE (operands[0]) == XFmode + || GET_MODE (operands[0]) == DFmode + || GET_MODE (operands[0]) == SFmode) + && (operands[2] = find_constant_src (insn))" + [(set (match_dup 0) (match_dup 2))] { - switch (which_alternative) - { - case 0: - case 1: - return output_387_reg_move (insn, operands); - - case 2: - return standard_80387_constant_opcode (operands[1]); - - case 3: - case 4: - return "#"; + rtx c = operands[2]; + rtx r = operands[0]; - case 5: - switch (get_attr_mode (insn)) - { - case MODE_V4SF: - return "xorps\t%0, %0"; - case MODE_V2DF: - return "xorpd\t%0, %0"; - case MODE_TI: - return "pxor\t%0, %0"; - default: - gcc_unreachable (); - } - case 6: - case 7: - case 8: - switch (get_attr_mode (insn)) - { - case MODE_V4SF: - return "movaps\t{%1, %0|%0, %1}"; - case MODE_V2DF: - return "movapd\t{%1, %0|%0, %1}"; - case MODE_TI: - return "movdqa\t{%1, %0|%0, %1}"; - case MODE_DI: - return "movq\t{%1, %0|%0, %1}"; - case MODE_DF: - return "movsd\t{%1, %0|%0, %1}"; - case MODE_V1DF: - return "movlpd\t{%1, %0|%0, %1}"; - case MODE_V2SF: - return "movlps\t{%1, %0|%0, %1}"; - default: - gcc_unreachable (); - } + if (GET_CODE (r) == SUBREG) + r = SUBREG_REG (r); - default: - gcc_unreachable(); + if (SSE_REG_P (r)) + { + if (!standard_sse_constant_p (c)) + FAIL; } -} - [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov") - (set (attr "prefix_data16") - (if_then_else (eq_attr "mode" "V1DF") - (const_string "1") - (const_string "*"))) - (set (attr "mode") - (cond [(eq_attr "alternative" "0,1,2") - (const_string "DF") - (eq_attr "alternative" "3,4") - (const_string "SI") - - /* For SSE1, we have many fewer alternatives. */ - (eq (symbol_ref "TARGET_SSE2") (const_int 0)) - (cond [(eq_attr "alternative" "5,6") - (const_string "V4SF") - ] - (const_string "V2SF")) + else if (FP_REG_P (r)) + { + if (!standard_80387_constant_p (c)) + FAIL; + } + else if (MMX_REG_P (r)) + FAIL; +}) - /* xorps is one byte shorter. */ - (eq_attr "alternative" "5") - (cond [(ne (symbol_ref "optimize_function_for_size_p (cfun)") - (const_int 0)) - (const_string "V4SF") - (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR") - (const_int 0)) - (const_string "TI") - ] - (const_string "V2DF")) +(define_split + [(set (match_operand 0 "register_operand" "") + (float_extend (match_operand 1 "memory_operand" "")))] + "reload_completed + && MEM_P (operands[1]) + && (GET_MODE (operands[0]) == TFmode + || GET_MODE (operands[0]) == XFmode + || GET_MODE (operands[0]) == DFmode + || GET_MODE (operands[0]) == SFmode) + && (operands[2] = find_constant_src (insn))" + [(set (match_dup 0) (match_dup 2))] +{ + rtx c = operands[2]; + rtx r = operands[0]; - /* For architectures resolving dependencies on - whole SSE registers use APD move to break dependency - chains, otherwise use short move to avoid extra work. + if (GET_CODE (r) == SUBREG) + r = SUBREG_REG (r); - movaps encodes one byte shorter. */ - (eq_attr "alternative" "6") - (cond - [(ne (symbol_ref "optimize_function_for_size_p (cfun)") - (const_int 0)) - (const_string "V4SF") - (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY") - (const_int 0)) - (const_string "V2DF") - ] - (const_string "DF")) - /* For architectures resolving dependencies on register - parts we may avoid extra work to zero out upper part - of register. */ - (eq_attr "alternative" "7") - (if_then_else - (ne (symbol_ref "TARGET_SSE_SPLIT_REGS") - (const_int 0)) - (const_string "V1DF") - (const_string "DF")) - ] - (const_string "DF")))]) + if (SSE_REG_P (r)) + { + if (!standard_sse_constant_p (c)) + FAIL; + } + else if (FP_REG_P (r)) + { + if (!standard_80387_constant_p (c)) + FAIL; + } + else if (MMX_REG_P (r)) + FAIL; +}) +;; Split the load of -0.0 or -1.0 into fldz;fchs or fld1;fchs sequence (define_split - [(set (match_operand:DF 0 "nonimmediate_operand" "") - (match_operand:DF 1 "general_operand" ""))] - "reload_completed - && !(MEM_P (operands[0]) && MEM_P (operands[1])) - && ! (ANY_FP_REG_P (operands[0]) || - (GET_CODE (operands[0]) == SUBREG - && ANY_FP_REG_P (SUBREG_REG (operands[0])))) - && ! (ANY_FP_REG_P (operands[1]) || - (GET_CODE (operands[1]) == SUBREG - && ANY_FP_REG_P (SUBREG_REG (operands[1]))))" - [(const_int 0)] - "ix86_split_long_move (operands); DONE;") + [(set (match_operand:X87MODEF 0 "register_operand" "") + (match_operand:X87MODEF 1 "immediate_operand" ""))] + "reload_completed && FP_REGNO_P (REGNO (operands[0])) + && (standard_80387_constant_p (operands[1]) == 8 + || standard_80387_constant_p (operands[1]) == 9)" + [(set (match_dup 0)(match_dup 1)) + (set (match_dup 0) + (neg:X87MODEF (match_dup 0)))] +{ + REAL_VALUE_TYPE r; + + REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); + if (real_isnegzero (&r)) + operands[1] = CONST0_RTX (mode); + else + operands[1] = CONST1_RTX (mode); +}) -(define_insn "*swapdf" - [(set (match_operand:DF 0 "fp_register_operand" "+f") - (match_operand:DF 1 "fp_register_operand" "+f")) +(define_insn "swapxf" + [(set (match_operand:XF 0 "register_operand" "+f") + (match_operand:XF 1 "register_operand" "+f")) (set (match_dup 1) (match_dup 0))] - "reload_completed || TARGET_80387" + "TARGET_80387" { if (STACK_TOP_P (operands[0])) return "fxch\t%1"; @@ -3665,437 +3584,136 @@ return "fxch\t%0"; } [(set_attr "type" "fxch") - (set_attr "mode" "DF")]) - -(define_expand "movxf" - [(set (match_operand:XF 0 "nonimmediate_operand" "") - (match_operand:XF 1 "general_operand" ""))] - "" - "ix86_expand_move (XFmode, operands); DONE;") - -;; Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size. -;; Size of pushdf using integer instructions is 3+3*memory operand size -;; Pushing using integer instructions is longer except for constants -;; and direct memory references. -;; (assuming that any given constant is pushed only once, but this ought to be -;; handled elsewhere). + (set_attr "mode" "XF")]) -(define_insn "*pushxf_nointeger" - [(set (match_operand:XF 0 "push_operand" "=X,X,X") - (match_operand:XF 1 "general_no_elim_operand" "f,Fo,*r"))] - "optimize_function_for_size_p (cfun)" -{ - /* This insn should be already split before reg-stack. */ - gcc_unreachable (); -} - [(set_attr "type" "multi") - (set_attr "unit" "i387,*,*") - (set_attr "mode" "XF,SI,SI")]) - -(define_insn "*pushxf_integer" - [(set (match_operand:XF 0 "push_operand" "=<,<") - (match_operand:XF 1 "general_no_elim_operand" "f,ro"))] - "optimize_function_for_speed_p (cfun)" +(define_insn "*swap" + [(set (match_operand:MODEF 0 "fp_register_operand" "+f") + (match_operand:MODEF 1 "fp_register_operand" "+f")) + (set (match_dup 1) + (match_dup 0))] + "TARGET_80387 || reload_completed" { - /* This insn should be already split before reg-stack. */ - gcc_unreachable (); + if (STACK_TOP_P (operands[0])) + return "fxch\t%1"; + else + return "fxch\t%0"; } - [(set_attr "type" "multi") - (set_attr "unit" "i387,*") - (set_attr "mode" "XF,SI")]) - -(define_split - [(set (match_operand 0 "push_operand" "") - (match_operand 1 "general_operand" ""))] - "reload_completed - && (GET_MODE (operands[0]) == XFmode - || GET_MODE (operands[0]) == DFmode) - && !ANY_FP_REG_P (operands[1])" - [(const_int 0)] - "ix86_split_long_move (operands); DONE;") + [(set_attr "type" "fxch") + (set_attr "mode" "")]) + +;; Zero extension instructions -(define_split - [(set (match_operand:XF 0 "push_operand" "") - (match_operand:XF 1 "any_fp_register_operand" ""))] +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] "" - [(set (reg:P SP_REG) (plus:P (reg:P SP_REG) (match_dup 2))) - (set (mem:XF (reg:P SP_REG)) (match_dup 1))] - "operands[2] = GEN_INT (TARGET_128BIT_LONG_DOUBLE ? -16 : -12);") - -;; Do not use integer registers when optimizing for size -(define_insn "*movxf_nointeger" - [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,*r,o") - (match_operand:XF 1 "general_operand" "fm,f,G,*roF,F*r"))] - "optimize_function_for_size_p (cfun) - && !(MEM_P (operands[0]) && MEM_P (operands[1])) - && (reload_in_progress || reload_completed - || standard_80387_constant_p (operands[1]) - || GET_CODE (operands[1]) != CONST_DOUBLE - || memory_operand (operands[0], XFmode))" { - switch (which_alternative) + if (TARGET_ZERO_EXTEND_WITH_AND && optimize_function_for_speed_p (cfun)) { - case 0: - case 1: - return output_387_reg_move (insn, operands); - - case 2: - return standard_80387_constant_opcode (operands[1]); - - case 3: case 4: - return "#"; - default: - gcc_unreachable (); + operands[1] = force_reg (HImode, operands[1]); + emit_insn (gen_zero_extendhisi2_and (operands[0], operands[1])); + DONE; } -} - [(set_attr "type" "fmov,fmov,fmov,multi,multi") - (set_attr "mode" "XF,XF,XF,SI,SI")]) +}) -(define_insn "*movxf_integer" - [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,r,o") - (match_operand:XF 1 "general_operand" "fm,f,G,roF,Fr"))] - "optimize_function_for_speed_p (cfun) - && !(MEM_P (operands[0]) && MEM_P (operands[1])) - && (reload_in_progress || reload_completed - || GET_CODE (operands[1]) != CONST_DOUBLE - || memory_operand (operands[0], XFmode))" -{ - switch (which_alternative) - { - case 0: - case 1: - return output_387_reg_move (insn, operands); +(define_insn "zero_extendhisi2_and" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "register_operand" "0"))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_ZERO_EXTEND_WITH_AND && optimize_function_for_speed_p (cfun)" + "#" + [(set_attr "type" "alu1") + (set_attr "mode" "SI")]) - case 2: - return standard_80387_constant_opcode (operands[1]); +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "register_operand" ""))) + (clobber (reg:CC FLAGS_REG))] + "reload_completed && TARGET_ZERO_EXTEND_WITH_AND + && optimize_function_for_speed_p (cfun)" + [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (const_int 65535))) + (clobber (reg:CC FLAGS_REG))])] + "") - case 3: case 4: - return "#"; +(define_insn "*zero_extendhisi2_movzwl" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))] + "!TARGET_ZERO_EXTEND_WITH_AND + || optimize_function_for_size_p (cfun)" + "movz{wl|x}\t{%1, %0|%0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "SI")]) - default: - gcc_unreachable (); - } -} - [(set_attr "type" "fmov,fmov,fmov,multi,multi") - (set_attr "mode" "XF,XF,XF,SI,SI")]) +(define_expand "zero_extendqihi2" + [(parallel + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC FLAGS_REG))])] + "" + "") -(define_expand "movtf" - [(set (match_operand:TF 0 "nonimmediate_operand" "") - (match_operand:TF 1 "nonimmediate_operand" ""))] - "TARGET_SSE2" -{ - ix86_expand_move (TFmode, operands); - DONE; -}) +(define_insn "*zero_extendqihi2_and" + [(set (match_operand:HI 0 "register_operand" "=r,?&q") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,qm"))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_ZERO_EXTEND_WITH_AND && optimize_function_for_speed_p (cfun)" + "#" + [(set_attr "type" "alu1") + (set_attr "mode" "HI")]) -(define_insn "*movtf_internal" - [(set (match_operand:TF 0 "nonimmediate_operand" "=x,m,x,?r,?o") - (match_operand:TF 1 "general_operand" "xm,x,C,roF,Fr"))] - "TARGET_SSE2 - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" -{ - switch (which_alternative) - { - case 0: - case 1: - if (get_attr_mode (insn) == MODE_V4SF) - return "%vmovaps\t{%1, %0|%0, %1}"; - else - return "%vmovdqa\t{%1, %0|%0, %1}"; - case 2: - if (get_attr_mode (insn) == MODE_V4SF) - return "%vxorps\t%0, %d0"; - else - return "%vpxor\t%0, %d0"; - case 3: - case 4: - return "#"; - default: - gcc_unreachable (); - } -} - [(set_attr "type" "ssemov,ssemov,sselog1,*,*") - (set_attr "prefix" "maybe_vex,maybe_vex,maybe_vex,*,*") - (set (attr "mode") - (cond [(eq_attr "alternative" "0,2") - (if_then_else - (ne (symbol_ref "optimize_function_for_size_p (cfun)") - (const_int 0)) - (const_string "V4SF") - (const_string "TI")) - (eq_attr "alternative" "1") - (if_then_else - (ior (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES") - (const_int 0)) - (ne (symbol_ref "optimize_function_for_size_p (cfun)") - (const_int 0))) - (const_string "V4SF") - (const_string "TI"))] - (const_string "DI")))]) +(define_insn "*zero_extendqihi2_movzbw_and" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm,0"))) + (clobber (reg:CC FLAGS_REG))] + "!TARGET_ZERO_EXTEND_WITH_AND || optimize_function_for_size_p (cfun)" + "#" + [(set_attr "type" "imovx,alu1") + (set_attr "mode" "HI")]) -(define_insn "*pushtf_sse" - [(set (match_operand:TF 0 "push_operand" "=<,<,<") - (match_operand:TF 1 "general_no_elim_operand" "x,Fo,*r"))] - "TARGET_SSE2" -{ - /* This insn should be already split before reg-stack. */ - gcc_unreachable (); -} - [(set_attr "type" "multi") - (set_attr "unit" "sse,*,*") - (set_attr "mode" "TF,SI,SI")]) +; zero extend to SImode here to avoid partial register stalls +(define_insn "*zero_extendqihi2_movzbl" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))] + "(!TARGET_ZERO_EXTEND_WITH_AND || optimize_function_for_size_p (cfun)) + && reload_completed" + "movz{bl|x}\t{%1, %k0|%k0, %1}" + [(set_attr "type" "imovx") + (set_attr "mode" "SI")]) +;; For the movzbw case strip only the clobber (define_split - [(set (match_operand:TF 0 "push_operand" "") - (match_operand:TF 1 "general_operand" ""))] - "TARGET_SSE2 && reload_completed - && !SSE_REG_P (operands[1])" - [(const_int 0)] - "ix86_split_long_move (operands); DONE;") + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC FLAGS_REG))] + "reload_completed + && (!TARGET_ZERO_EXTEND_WITH_AND + || optimize_function_for_size_p (cfun)) + && (!REG_P (operands[1]) || ANY_QI_REG_P (operands[1]))" + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]) +;; When source and destination does not overlap, clear destination +;; first and then do the movb (define_split - [(set (match_operand:TF 0 "push_operand" "") - (match_operand:TF 1 "any_fp_register_operand" ""))] - "TARGET_SSE2" - [(set (reg:P SP_REG) (plus:P (reg:P SP_REG) (const_int -16))) - (set (mem:TF (reg:P SP_REG)) (match_dup 1))] - "") + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) + (clobber (reg:CC FLAGS_REG))] + "reload_completed + && ANY_QI_REG_P (operands[0]) + && (TARGET_ZERO_EXTEND_WITH_AND + && optimize_function_for_speed_p (cfun)) + && !reg_overlap_mentioned_p (operands[0], operands[1])" + [(set (strict_low_part (match_dup 2)) (match_dup 1))] +{ + operands[2] = gen_lowpart (QImode, operands[0]); + ix86_expand_clear (operands[0]); +}) +;; Rest is handled by single and. (define_split - [(set (match_operand 0 "nonimmediate_operand" "") - (match_operand 1 "general_operand" ""))] - "reload_completed - && !(MEM_P (operands[0]) && MEM_P (operands[1])) - && GET_MODE (operands[0]) == XFmode - && ! (ANY_FP_REG_P (operands[0]) || - (GET_CODE (operands[0]) == SUBREG - && ANY_FP_REG_P (SUBREG_REG (operands[0])))) - && ! (ANY_FP_REG_P (operands[1]) || - (GET_CODE (operands[1]) == SUBREG - && ANY_FP_REG_P (SUBREG_REG (operands[1]))))" - [(const_int 0)] - "ix86_split_long_move (operands); DONE;") - -(define_split - [(set (match_operand 0 "register_operand" "") - (match_operand 1 "memory_operand" ""))] - "reload_completed - && MEM_P (operands[1]) - && (GET_MODE (operands[0]) == TFmode - || GET_MODE (operands[0]) == XFmode - || GET_MODE (operands[0]) == SFmode - || GET_MODE (operands[0]) == DFmode) - && (operands[2] = find_constant_src (insn))" - [(set (match_dup 0) (match_dup 2))] -{ - rtx c = operands[2]; - rtx r = operands[0]; - - if (GET_CODE (r) == SUBREG) - r = SUBREG_REG (r); - - if (SSE_REG_P (r)) - { - if (!standard_sse_constant_p (c)) - FAIL; - } - else if (FP_REG_P (r)) - { - if (!standard_80387_constant_p (c)) - FAIL; - } - else if (MMX_REG_P (r)) - FAIL; -}) - -(define_split - [(set (match_operand 0 "register_operand" "") - (float_extend (match_operand 1 "memory_operand" "")))] - "reload_completed - && MEM_P (operands[1]) - && (GET_MODE (operands[0]) == TFmode - || GET_MODE (operands[0]) == XFmode - || GET_MODE (operands[0]) == SFmode - || GET_MODE (operands[0]) == DFmode) - && (operands[2] = find_constant_src (insn))" - [(set (match_dup 0) (match_dup 2))] -{ - rtx c = operands[2]; - rtx r = operands[0]; - - if (GET_CODE (r) == SUBREG) - r = SUBREG_REG (r); - - if (SSE_REG_P (r)) - { - if (!standard_sse_constant_p (c)) - FAIL; - } - else if (FP_REG_P (r)) - { - if (!standard_80387_constant_p (c)) - FAIL; - } - else if (MMX_REG_P (r)) - FAIL; -}) - -(define_insn "swapxf" - [(set (match_operand:XF 0 "register_operand" "+f") - (match_operand:XF 1 "register_operand" "+f")) - (set (match_dup 1) - (match_dup 0))] - "TARGET_80387" -{ - if (STACK_TOP_P (operands[0])) - return "fxch\t%1"; - else - return "fxch\t%0"; -} - [(set_attr "type" "fxch") - (set_attr "mode" "XF")]) - -;; Split the load of -0.0 or -1.0 into fldz;fchs or fld1;fchs sequence -(define_split - [(set (match_operand:X87MODEF 0 "register_operand" "") - (match_operand:X87MODEF 1 "immediate_operand" ""))] - "reload_completed && FP_REGNO_P (REGNO (operands[0])) - && (standard_80387_constant_p (operands[1]) == 8 - || standard_80387_constant_p (operands[1]) == 9)" - [(set (match_dup 0)(match_dup 1)) - (set (match_dup 0) - (neg:X87MODEF (match_dup 0)))] -{ - REAL_VALUE_TYPE r; - - REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); - if (real_isnegzero (&r)) - operands[1] = CONST0_RTX (mode); - else - operands[1] = CONST1_RTX (mode); -}) - -(define_split - [(set (match_operand:TF 0 "nonimmediate_operand" "") - (match_operand:TF 1 "general_operand" ""))] - "reload_completed - && !(SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]))" - [(const_int 0)] - "ix86_split_long_move (operands); DONE;") - -;; Zero extension instructions - -(define_expand "zero_extendhisi2" - [(set (match_operand:SI 0 "register_operand" "") - (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] - "" -{ - if (TARGET_ZERO_EXTEND_WITH_AND && optimize_function_for_speed_p (cfun)) - { - operands[1] = force_reg (HImode, operands[1]); - emit_insn (gen_zero_extendhisi2_and (operands[0], operands[1])); - DONE; - } -}) - -(define_insn "zero_extendhisi2_and" - [(set (match_operand:SI 0 "register_operand" "=r") - (zero_extend:SI (match_operand:HI 1 "register_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_ZERO_EXTEND_WITH_AND && optimize_function_for_speed_p (cfun)" - "#" - [(set_attr "type" "alu1") - (set_attr "mode" "SI")]) - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (zero_extend:SI (match_operand:HI 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "reload_completed && TARGET_ZERO_EXTEND_WITH_AND - && optimize_function_for_speed_p (cfun)" - [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (const_int 65535))) - (clobber (reg:CC FLAGS_REG))])] - "") - -(define_insn "*zero_extendhisi2_movzwl" - [(set (match_operand:SI 0 "register_operand" "=r") - (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))] - "!TARGET_ZERO_EXTEND_WITH_AND - || optimize_function_for_size_p (cfun)" - "movz{wl|x}\t{%1, %0|%0, %1}" - [(set_attr "type" "imovx") - (set_attr "mode" "SI")]) - -(define_expand "zero_extendqihi2" - [(parallel - [(set (match_operand:HI 0 "register_operand" "") - (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "" - "") - -(define_insn "*zero_extendqihi2_and" - [(set (match_operand:HI 0 "register_operand" "=r,?&q") - (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,qm"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_ZERO_EXTEND_WITH_AND && optimize_function_for_speed_p (cfun)" - "#" - [(set_attr "type" "alu1") - (set_attr "mode" "HI")]) - -(define_insn "*zero_extendqihi2_movzbw_and" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm,0"))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_ZERO_EXTEND_WITH_AND || optimize_function_for_size_p (cfun)" - "#" - [(set_attr "type" "imovx,alu1") - (set_attr "mode" "HI")]) - -; zero extend to SImode here to avoid partial register stalls -(define_insn "*zero_extendqihi2_movzbl" - [(set (match_operand:HI 0 "register_operand" "=r") - (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))] - "(!TARGET_ZERO_EXTEND_WITH_AND || optimize_function_for_size_p (cfun)) - && reload_completed" - "movz{bl|x}\t{%1, %k0|%k0, %1}" - [(set_attr "type" "imovx") - (set_attr "mode" "SI")]) - -;; For the movzbw case strip only the clobber -(define_split - [(set (match_operand:HI 0 "register_operand" "") - (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "reload_completed - && (!TARGET_ZERO_EXTEND_WITH_AND - || optimize_function_for_size_p (cfun)) - && (!REG_P (operands[1]) || ANY_QI_REG_P (operands[1]))" - [(set (match_operand:HI 0 "register_operand" "") - (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]) - -;; When source and destination does not overlap, clear destination -;; first and then do the movb -(define_split - [(set (match_operand:HI 0 "register_operand" "") - (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "reload_completed - && ANY_QI_REG_P (operands[0]) - && (TARGET_ZERO_EXTEND_WITH_AND - && optimize_function_for_speed_p (cfun)) - && !reg_overlap_mentioned_p (operands[0], operands[1])" - [(set (strict_low_part (match_dup 2)) (match_dup 1))] -{ - operands[2] = gen_lowpart (QImode, operands[0]); - ix86_expand_clear (operands[0]); -}) - -;; Rest is handled by single and. -(define_split - [(set (match_operand:HI 0 "register_operand" "") - (zero_extend:HI (match_operand:QI 1 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))] + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "register_operand" ""))) + (clobber (reg:CC FLAGS_REG))] "reload_completed && true_regnum (operands[0]) == true_regnum (operands[1])" [(parallel [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255))) @@ -4245,7 +3863,7 @@ (zero_extend:DI (match_operand:SI 1 "general_operand" ""))) (clobber (reg:CC FLAGS_REG))] "!TARGET_64BIT && reload_completed - && !SSE_REG_P (operands[0]) && !MMX_REG_P (operands[0])" + && !(MMX_REG_P (operands[0]) || SSE_REG_P (operands[0]))" [(set (match_dup 3) (match_dup 1)) (set (match_dup 4) (const_int 0))] "split_di (&operands[0], 1, &operands[3], &operands[4]);") @@ -4351,12 +3969,12 @@ && true_regnum (operands[1]) == AX_REG && true_regnum (operands[2]) == DX_REG) { - emit_insn (gen_ashrsi3_31 (operands[2], operands[1], GEN_INT (31))); + emit_insn (gen_ashrsi3_cvt (operands[2], operands[1], GEN_INT (31))); } else { emit_move_insn (operands[2], operands[1]); - emit_insn (gen_ashrsi3_31 (operands[2], operands[2], GEN_INT (31))); + emit_insn (gen_ashrsi3_cvt (operands[2], operands[2], GEN_INT (31))); } emit_move_insn (operands[4], operands[2]); DONE; @@ -4379,16 +3997,17 @@ /* Generate a cltd if possible and doing so it profitable. */ if ((optimize_function_for_size_p (cfun) || TARGET_USE_CLTD) - && true_regnum (operands[3]) == AX_REG) + && true_regnum (operands[3]) == AX_REG + && true_regnum (operands[4]) == DX_REG) { - emit_insn (gen_ashrsi3_31 (operands[4], operands[3], GEN_INT (31))); + emit_insn (gen_ashrsi3_cvt (operands[4], operands[3], GEN_INT (31))); DONE; } if (true_regnum (operands[4]) != true_regnum (operands[1])) emit_move_insn (operands[4], operands[1]); - emit_insn (gen_ashrsi3_31 (operands[4], operands[4], GEN_INT (31))); + emit_insn (gen_ashrsi3_cvt (operands[4], operands[4], GEN_INT (31))); DONE; }) @@ -4519,7 +4138,7 @@ "" [(set (reg:P SP_REG) (plus:P (reg:P SP_REG) (match_dup 2))) (set (mem:XF (reg:P SP_REG)) (float_extend:XF (match_dup 1)))] - "operands[2] = GEN_INT (TARGET_128BIT_LONG_DOUBLE ? -16 : -12);") + "operands[2] = GEN_INT (-GET_MODE_SIZE (XFmode));") (define_split [(set (match_operand:XF 0 "push_operand" "") @@ -4527,7 +4146,7 @@ "" [(set (reg:P SP_REG) (plus:P (reg:P SP_REG) (match_dup 2))) (set (mem:DF (reg:P SP_REG)) (float_extend:XF (match_dup 1)))] - "operands[2] = GEN_INT (TARGET_128BIT_LONG_DOUBLE ? -16 : -12);") + "operands[2] = GEN_INT (-GET_MODE_SIZE (XFmode));") (define_expand "extendsfdf2" [(set (match_operand:DF 0 "nonimmediate_operand" "") @@ -4587,7 +4206,8 @@ } else operands[3] = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0); - emit_insn (gen_sse_unpcklps (operands[3], operands[3], operands[3])); + emit_insn (gen_vec_interleave_lowv4sf (operands[3], operands[3], + operands[3])); } else emit_insn (gen_vec_setv4sf_0 (operands[3], @@ -5120,6 +4740,7 @@ (set (match_operand:SSEMODEI24 2 "register_operand" "") (fix:SSEMODEI24 (match_dup 0)))] "TARGET_SHORTEN_X87_SSE + && !(TARGET_AVOID_VECTOR_DECODE && optimize_insn_for_speed_p ()) && peep2_reg_dead_p (2, operands[0])" [(set (match_dup 2) (fix:SSEMODEI24 (match_dup 1)))] "") @@ -5468,7 +5089,6 @@ "TARGET_80387 || ((mode != DImode || TARGET_64BIT) && SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)" - " { if (!((mode != DImode || TARGET_64BIT) && SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) @@ -5489,7 +5109,7 @@ emit_insn (insn); DONE; } -}") +}) ;; Pre-reload splitter to add memory clobber to the pattern. (define_insn_and_split "*float2_1" @@ -5984,7 +5604,8 @@ gen_rtx_SUBREG (SImode, operands[1], 0))); emit_insn (gen_sse2_loadld (operands[4], CONST0_RTX (V4SImode), gen_rtx_SUBREG (SImode, operands[1], 4))); - emit_insn (gen_sse2_punpckldq (operands[3], operands[3], operands[4])); + emit_insn (gen_vec_interleave_lowv4si (operands[3], operands[3], + operands[4])); operands[3] = gen_rtx_REG (DImode, REGNO (operands[3])); }) @@ -6125,42 +5746,13 @@ (plus:DWIH (match_dup 1) (match_dup 2)))]) (parallel [(set (match_dup 3) (plus:DWIH + (match_dup 4) (plus:DWIH (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0)) - (match_dup 4)) - (match_dup 5))) + (match_dup 5)))) (clobber (reg:CC FLAGS_REG))])] "split_ (&operands[0], 3, &operands[0], &operands[3]);") -(define_insn "add3_carry" - [(set (match_operand:SWI 0 "nonimmediate_operand" "=m,") - (plus:SWI - (plus:SWI (match_operand:SWI 3 "ix86_carry_flag_operator" "") - (match_operand:SWI 1 "nonimmediate_operand" "%0,0")) - (match_operand:SWI 2 "" ",m"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (PLUS, mode, operands)" - "adc{}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "use_carry" "1") - (set_attr "pent_pair" "pu") - (set_attr "mode" "")]) - -(define_insn "*addsi3_carry_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (plus:SI - (plus:SI (match_operand:SI 3 "ix86_carry_flag_operator" "") - (match_operand:SI 1 "nonimmediate_operand" "%0")) - (match_operand:SI 2 "general_operand" "g")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (PLUS, SImode, operands)" - "adc{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "alu") - (set_attr "use_carry" "1") - (set_attr "pent_pair" "pu") - (set_attr "mode" "SI")]) - (define_insn "*add3_cc" [(set (reg:CC FLAGS_REG) (unspec:CC @@ -6187,19 +5779,6 @@ [(set_attr "type" "alu") (set_attr "mode" "QI")]) -(define_insn "*add3_cconly_overflow" - [(set (reg:CCC FLAGS_REG) - (compare:CCC - (plus:SWI - (match_operand:SWI 1 "nonimmediate_operand" "%0") - (match_operand:SWI 2 "" "m")) - (match_dup 1))) - (clobber (match_scratch:SWI 0 "="))] - "ix86_binary_operator_ok (PLUS, mode, operands)" - "add{}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "")]) - (define_insn "*lea_1" [(set (match_operand:DWIH 0 "register_operand" "=r") (match_operand:DWIH 1 "no_seg_address_operand" "p"))] @@ -6255,20 +5834,9 @@ return "add{}\t{%1, %0|%0, %1}"; gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (x86_maybe_negate_const_int (&operands[2], mode)) + return "sub{}\t{%2, %0|%0, %2}"; - /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - /* Avoid overflows. */ - && (mode != DImode - || ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{}\t{%2, %0|%0, %2}"; - } return "add{}\t{%2, %0|%0, %2}"; } } @@ -6278,10 +5846,6 @@ (const_string "lea") (eq_attr "alternative" "3") (const_string "lea") - ; Current assemblers are broken and do not allow @GOTOFF in - ; ought but a memory context. - (match_operand:SWI48 2 "pic_symbolic_operand" "") - (const_string "lea") (match_operand:SWI48 2 "incdec_operand" "") (const_string "incdec") ] @@ -6323,26 +5887,15 @@ } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{l}\t{%2, %k0|%k0, %2}"; - } + if (x86_maybe_negate_const_int (&operands[2], SImode)) + return "sub{l}\t{%2, %k0|%k0, %2}"; + return "add{l}\t{%2, %k0|%k0, %2}"; } } [(set (attr "type") (cond [(eq_attr "alternative" "1") (const_string "lea") - ; Current assemblers are broken and do not allow @GOTOFF in - ; ought but a memory context. - (match_operand:SI 2 "pic_symbolic_operand" "") - (const_string "lea") (match_operand:SI 2 "incdec_operand" "") (const_string "incdec") ] @@ -6374,16 +5927,9 @@ } default: - /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{w}\t{%2, %0|%0, %2}"; - } + if (x86_maybe_negate_const_int (&operands[2], HImode)) + return "sub{w}\t{%2, %0|%0, %2}"; + return "add{w}\t{%2, %0|%0, %2}"; } } @@ -6414,7 +5960,9 @@ { case TYPE_LEA: return "#"; + case TYPE_INCDEC: + gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) return "inc{w}\t%0"; else @@ -6424,16 +5972,10 @@ } default: - /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{w}\t{%2, %0|%0, %2}"; - } + gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (x86_maybe_negate_const_int (&operands[2], HImode)) + return "sub{w}\t{%2, %0|%0, %2}"; + return "add{w}\t{%2, %0|%0, %2}"; } } @@ -6471,14 +6013,8 @@ } default: - /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) + if (x86_maybe_negate_const_int (&operands[2], QImode)) { - operands[2] = GEN_INT (-INTVAL (operands[2])); if (widen) return "sub{l}\t{%2, %k0|%k0, %2}"; else @@ -6515,7 +6051,9 @@ { case TYPE_LEA: return "#"; + case TYPE_INCDEC: + gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) return widen ? "inc{l}\t%k0" : "inc{b}\t%0"; else @@ -6525,14 +6063,9 @@ } default: - /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) + gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (x86_maybe_negate_const_int (&operands[2], QImode)) { - operands[2] = GEN_INT (-INTVAL (operands[2])); if (widen) return "sub{l}\t{%2, %k0|%k0, %2}"; else @@ -6577,13 +6110,9 @@ } default: - /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. */ - if (CONST_INT_P (operands[1]) - && INTVAL (operands[1]) < 0) - { - operands[1] = GEN_INT (-INTVAL (operands[1])); - return "sub{b}\t{%1, %0|%0, %1}"; - } + if (x86_maybe_negate_const_int (&operands[1], QImode)) + return "sub{b}\t{%1, %0|%0, %1}"; + return "add{b}\t{%1, %0|%0, %1}"; } } @@ -6600,22 +6129,18 @@ (define_insn "*add_2" [(set (reg FLAGS_REG) (compare - (plus:SWI48 - (match_operand:SWI48 1 "nonimmediate_operand" "%0,0") - (match_operand:SWI48 2 "" ",r")) + (plus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "%0,0") + (match_operand:SWI 2 "" ",")) (const_int 0))) - (set (match_operand:SWI48 0 "nonimmediate_operand" "=r,rm") - (plus:SWI48 (match_dup 1) (match_dup 2)))] + (set (match_operand:SWI 0 "nonimmediate_operand" "=,m") + (plus:SWI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (PLUS, mode, operands) - /* Current assemblers are broken and do not allow @GOTOFF in - ought but a memory context. */ - && ! pic_symbolic_operand (operands[2], VOIDmode)" + && ix86_binary_operator_ok (PLUS, mode, operands)" { switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) return "inc{}\t%0"; else @@ -6625,27 +6150,14 @@ } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* ???? In DImode, we ought to handle there the 32bit case too - - do we need new constraint? */ - /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - /* Avoid overflows. */ - && (mode != DImode - || ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{}\t{%2, %0|%0, %2}"; - } + if (x86_maybe_negate_const_int (&operands[2], mode)) + return "sub{}\t{%2, %0|%0, %2}"; + return "add{}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:SWI48 2 "incdec_operand" "") + (if_then_else (match_operand:SWI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) (set (attr "length_immediate") @@ -6665,10 +6177,7 @@ (set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (plus:SI (match_dup 1) (match_dup 2))))] "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (PLUS, SImode, operands) - /* Current assemblers are broken and do not allow @GOTOFF in - ought but a memory context. */ - && ! pic_symbolic_operand (operands[2], VOIDmode)" + && ix86_binary_operator_ok (PLUS, SImode, operands)" { switch (get_attr_type (insn)) { @@ -6682,16 +6191,9 @@ } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{l}\t{%2, %k0|%k0, %2}"; - } + if (x86_maybe_negate_const_int (&operands[2], SImode)) + return "sub{l}\t{%2, %k0|%k0, %2}"; + return "add{l}\t{%2, %k0|%k0, %2}"; } } @@ -6706,110 +6208,18 @@ (const_string "*"))) (set_attr "mode" "SI")]) -(define_insn "*addhi_2" - [(set (reg FLAGS_REG) - (compare - (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") - (match_operand:HI 2 "general_operand" "rmn,rn")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") - (plus:HI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (PLUS, HImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{w}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; - } - - default: - /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{w}\t{%2, %0|%0, %2}"; - } - return "add{w}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:HI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set (attr "length_immediate") - (if_then_else - (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) - (const_string "1") - (const_string "*"))) - (set_attr "mode" "HI")]) - -(define_insn "*addqi_2" - [(set (reg FLAGS_REG) - (compare - (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") - (match_operand:QI 2 "general_operand" "qmn,qn")) - (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm") - (plus:QI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (PLUS, QImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%0"; - } - - default: - /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. */ - if (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) < 0) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{b}\t{%2, %0|%0, %2}"; - } - return "add{b}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:QI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set_attr "mode" "QI")]) - (define_insn "*add_3" [(set (reg FLAGS_REG) (compare - (neg:SWI48 (match_operand:SWI48 2 "" "")) - (match_operand:SWI48 1 "nonimmediate_operand" "%0"))) - (clobber (match_scratch:SWI48 0 "=r"))] + (neg:SWI (match_operand:SWI 2 "" "")) + (match_operand:SWI 1 "nonimmediate_operand" "%0"))) + (clobber (match_scratch:SWI 0 "="))] "ix86_match_ccmode (insn, CCZmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2])) - /* Current assemblers are broken and do not allow @GOTOFF in - ought but a memory context. */ - && ! pic_symbolic_operand (operands[2], VOIDmode)" + && !(MEM_P (operands[1]) && MEM_P (operands[2]))" { switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) return "inc{}\t%0"; else @@ -6819,27 +6229,14 @@ } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* ???? In DImode, we ought to handle there the 32bit case too - - do we need new constraint? */ - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - /* Avoid overflows. */ - && (mode != DImode - || ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{}\t{%2, %0|%0, %2}"; - } + if (x86_maybe_negate_const_int (&operands[2], mode)) + return "sub{}\t{%2, %0|%0, %2}"; + return "add{}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:SWI48 2 "incdec_operand" "") + (if_then_else (match_operand:SWI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) (set (attr "length_immediate") @@ -6858,10 +6255,7 @@ (set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (plus:SI (match_dup 1) (match_dup 2))))] "TARGET_64BIT && ix86_match_ccmode (insn, CCZmode) - && ix86_binary_operator_ok (PLUS, SImode, operands) - /* Current assemblers are broken and do not allow @GOTOFF in - ought but a memory context. */ - && ! pic_symbolic_operand (operands[2], VOIDmode)" + && ix86_binary_operator_ok (PLUS, SImode, operands)" { switch (get_attr_type (insn)) { @@ -6875,16 +6269,9 @@ } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{l}\t{%2, %k0|%k0, %2}"; - } + if (x86_maybe_negate_const_int (&operands[2], SImode)) + return "sub{l}\t{%2, %k0|%k0, %2}"; + return "add{l}\t{%2, %k0|%k0, %2}"; } } @@ -6899,96 +6286,10 @@ (const_string "*"))) (set_attr "mode" "SI")]) -(define_insn "*addhi_3" - [(set (reg FLAGS_REG) - (compare - (neg:HI (match_operand:HI 2 "general_operand" "rmn")) - (match_operand:HI 1 "nonimmediate_operand" "%0"))) - (clobber (match_scratch:HI 0 "=r"))] - "ix86_match_ccmode (insn, CCZmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{w}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; - } - - default: - /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{w}\t{%2, %0|%0, %2}"; - } - return "add{w}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:HI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set (attr "length_immediate") - (if_then_else - (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) - (const_string "1") - (const_string "*"))) - (set_attr "mode" "HI")]) - -(define_insn "*addqi_3" - [(set (reg FLAGS_REG) - (compare - (neg:QI (match_operand:QI 2 "general_operand" "qmn")) - (match_operand:QI 1 "nonimmediate_operand" "%0"))) - (clobber (match_scratch:QI 0 "=q"))] - "ix86_match_ccmode (insn, CCZmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%0"; - } - - default: - /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. */ - if (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) < 0) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{b}\t{%2, %0|%0, %2}"; - } - return "add{b}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:QI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set_attr "mode" "QI")]) - ; For comparisons against 1, -1 and 128, we may generate better code ; by converting cmp to add, inc or dec as done by peephole2. This pattern ; is matched then. We can't accept general immediate, because for ; case of overflows, the result is messed up. -; This pattern also don't hold of 0x8000000000000000, since the value -; overflows when negated. ; Also carry flag is reversed compared to cmp, so this conversion is valid ; only for comparisons not depending on it. @@ -7013,17 +6314,10 @@ } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if ((INTVAL (operands[2]) == -128 - || (INTVAL (operands[2]) > 0 - && INTVAL (operands[2]) != 128)) - /* Avoid overflows. */ - && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) - return "sub{q}\t{%2, %0|%0, %2}"; - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "add{q}\t{%2, %0|%0, %2}"; + if (x86_maybe_negate_const_int (&operands[2], DImode)) + return "add{q}\t{%2, %0|%0, %2}"; + + return "sub{q}\t{%2, %0|%0, %2}"; } } [(set (attr "type") @@ -7041,45 +6335,37 @@ ; by converting cmp to add, inc or dec as done by peephole2. This pattern ; is matched then. We can't accept general immediate, because for ; case of overflows, the result is messed up. -; This pattern also don't hold of 0x80000000, since the value overflows -; when negated. ; Also carry flag is reversed compared to cmp, so this conversion is valid ; only for comparisons not depending on it. -(define_insn "*addsi_4" +(define_insn "*add_4" [(set (reg FLAGS_REG) (compare - (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_scratch:SI 0 "=rm"))] - "ix86_match_ccmode (insn, CCGCmode) - && (INTVAL (operands[2]) & 0xffffffff) != 0x80000000" + (match_operand:SWI124 1 "nonimmediate_operand" "0") + (match_operand:SWI124 2 "const_int_operand" "n"))) + (clobber (match_scratch:SWI124 0 "=m"))] + "ix86_match_ccmode (insn, CCGCmode)" { switch (get_attr_type (insn)) { case TYPE_INCDEC: if (operands[2] == constm1_rtx) - return "inc{l}\t%0"; + return "inc{}\t%0"; else { gcc_assert (operands[2] == const1_rtx); - return "dec{l}\t%0"; + return "dec{}\t%0"; } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if ((INTVAL (operands[2]) == -128 - || (INTVAL (operands[2]) > 0 - && INTVAL (operands[2]) != 128))) - return "sub{l}\t{%2, %0|%0, %2}"; - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "add{l}\t{%2, %0|%0, %2}"; + if (x86_maybe_negate_const_int (&operands[2], mode)) + return "add{}\t{%2, %0|%0, %2}"; + + return "sub{}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:SI 2 "incdec_operand" "") + (if_then_else (match_operand: 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) (set (attr "length_immediate") @@ -7087,44 +6373,39 @@ (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "SI")]) - -; See comments above addsi_4 for details. + (set_attr "mode" "")]) -(define_insn "*addhi_4" +(define_insn "*add_5" [(set (reg FLAGS_REG) (compare - (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:HI 2 "const_int_operand" "n"))) - (clobber (match_scratch:HI 0 "=rm"))] - "ix86_match_ccmode (insn, CCGCmode) - && (INTVAL (operands[2]) & 0xffff) != 0x8000" + (plus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "%0") + (match_operand:SWI 2 "" "")) + (const_int 0))) + (clobber (match_scratch:SWI 0 "="))] + "ix86_match_ccmode (insn, CCGOCmode) + && !(MEM_P (operands[1]) && MEM_P (operands[2]))" { switch (get_attr_type (insn)) { case TYPE_INCDEC: - if (operands[2] == constm1_rtx) - return "inc{w}\t%0"; + if (operands[2] == const1_rtx) + return "inc{}\t%0"; else - { - gcc_assert (operands[2] == const1_rtx); - return "dec{w}\t%0"; + { + gcc_assert (operands[2] == constm1_rtx); + return "dec{}\t%0"; } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if ((INTVAL (operands[2]) == -128 - || (INTVAL (operands[2]) > 0 - && INTVAL (operands[2]) != 128))) - return "sub{w}\t{%2, %0|%0, %2}"; - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "add{w}\t{%2, %0|%0, %2}"; + if (x86_maybe_negate_const_int (&operands[2], mode)) + return "sub{}\t{%2, %0|%0, %2}"; + + return "add{}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:HI 2 "incdec_operand" "") + (if_then_else (match_operand:SWI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) (set (attr "length_immediate") @@ -7132,249 +6413,64 @@ (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "HI")]) - -; See comments above addsi_4 for details. + (set_attr "mode" "")]) -(define_insn "*addqi_4" - [(set (reg FLAGS_REG) - (compare - (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_int_operand" "n"))) - (clobber (match_scratch:QI 0 "=qm"))] - "ix86_match_ccmode (insn, CCGCmode) - && (INTVAL (operands[2]) & 0xff) != 0x80" +(define_insn "*addqi_ext_1_rex64" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (plus:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (match_operand:QI 2 "nonmemory_operand" "Qn"))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT" { switch (get_attr_type (insn)) { case TYPE_INCDEC: - if (operands[2] == constm1_rtx - || (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 255)) - return "inc{b}\t%0"; + if (operands[2] == const1_rtx) + return "inc{b}\t%h0"; else - { - gcc_assert (operands[2] == const1_rtx); - return "dec{b}\t%0"; - } - - default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - if (INTVAL (operands[2]) < 0) { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "add{b}\t{%2, %0|%0, %2}"; + gcc_assert (operands[2] == constm1_rtx); + return "dec{b}\t%h0"; } - return "sub{b}\t{%2, %0|%0, %2}"; + + default: + return "add{b}\t{%2, %h0|%h0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:HI 2 "incdec_operand" "") + (if_then_else (match_operand:QI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) + (set_attr "modrm" "1") (set_attr "mode" "QI")]) -(define_insn "*add_5" - [(set (reg FLAGS_REG) - (compare - (plus:SWI48 - (match_operand:SWI48 1 "nonimmediate_operand" "%0") - (match_operand:SWI48 2 "" "")) - (const_int 0))) - (clobber (match_scratch:SWI48 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2])) - /* Current assemblers are broken and do not allow @GOTOFF in - ought but a memory context. */ - && ! pic_symbolic_operand (operands[2], VOIDmode)" +(define_insn "addqi_ext_1" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (plus:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (match_operand:QI 2 "general_operand" "Qmn"))) + (clobber (reg:CC FLAGS_REG))] + "!TARGET_64BIT" { switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) - return "inc{}\t%0"; + return "inc{b}\t%h0"; else { - gcc_assert (operands[2] == constm1_rtx); - return "dec{}\t%0"; - } - - default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - /* Avoid overflows. */ - && (mode != DImode - || ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{}\t{%2, %0|%0, %2}"; - } - return "add{}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:SWI48 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set (attr "length_immediate") - (if_then_else - (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) - (const_string "1") - (const_string "*"))) - (set_attr "mode" "")]) - -(define_insn "*addhi_5" - [(set (reg FLAGS_REG) - (compare - (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0") - (match_operand:HI 2 "general_operand" "rmn")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{w}\t%0"; - else - { gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; - } - - default: - /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{w}\t{%2, %0|%0, %2}"; - } - return "add{w}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:HI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set (attr "length_immediate") - (if_then_else - (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) - (const_string "1") - (const_string "*"))) - (set_attr "mode" "HI")]) - -(define_insn "*addqi_5" - [(set (reg FLAGS_REG) - (compare - (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0") - (match_operand:QI 2 "general_operand" "qmn")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "ix86_match_ccmode (insn, CCGOCmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%0"; - } - - default: - /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. */ - if (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) < 0) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{b}\t{%2, %0|%0, %2}"; - } - return "add{b}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:QI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set_attr "mode" "QI")]) - -(define_insn "*addqi_ext_1_rex64" - [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") - (const_int 8) - (const_int 8)) - (plus:SI - (zero_extract:SI - (match_operand 1 "ext_register_operand" "0") - (const_int 8) - (const_int 8)) - (match_operand:QI 2 "nonmemory_operand" "Qn"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{b}\t%h0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%h0"; - } - - default: - return "add{b}\t{%2, %h0|%h0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:QI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set_attr "modrm" "1") - (set_attr "mode" "QI")]) - -(define_insn "addqi_ext_1" - [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") - (const_int 8) - (const_int 8)) - (plus:SI - (zero_extract:SI - (match_operand 1 "ext_register_operand" "0") - (const_int 8) - (const_int 8)) - (match_operand:QI 2 "general_operand" "Qmn"))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{b}\t%h0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 255)); return "dec{b}\t%h0"; } @@ -7657,46 +6753,6 @@ (clobber (reg:CC FLAGS_REG))])] "split_ (&operands[0], 3, &operands[0], &operands[3]);") -(define_insn "sub3_carry" - [(set (match_operand:SWI 0 "nonimmediate_operand" "=m,") - (minus:SWI - (match_operand:SWI 1 "nonimmediate_operand" "0,0") - (plus:SWI - (match_operand:SWI 3 "ix86_carry_flag_operator" "") - (match_operand:SWI 2 "" ",m")))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (MINUS, mode, operands)" - "sbb{}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "use_carry" "1") - (set_attr "pent_pair" "pu") - (set_attr "mode" "")]) - -(define_insn "*subsi3_carry_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (minus:SI (match_operand:SI 1 "register_operand" "0") - (plus:SI (match_operand:SI 3 "ix86_carry_flag_operator" "") - (match_operand:SI 2 "general_operand" "g"))))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (MINUS, SImode, operands)" - "sbb{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "alu") - (set_attr "pent_pair" "pu") - (set_attr "mode" "SI")]) - -(define_insn "*sub3_cconly_overflow" - [(set (reg:CCC FLAGS_REG) - (compare:CCC - (minus:SWI - (match_operand:SWI 0 "nonimmediate_operand" "m,") - (match_operand:SWI 1 "" ",m")) - (match_dup 0)))] - "" - "cmp{}\t{%1, %0|%0, %1}" - [(set_attr "type" "icmp") - (set_attr "mode" "")]) - (define_insn "*sub_1" [(set (match_operand:SWI 0 "nonimmediate_operand" "=m,") (minus:SWI @@ -7786,7 +6842,93 @@ "sub{l}\t{%2, %1|%1, %2}" [(set_attr "type" "alu") (set_attr "mode" "SI")]) + +;; Add with carry and subtract with borrow + +(define_expand "3_carry" + [(parallel + [(set (match_operand:SWI 0 "nonimmediate_operand" "") + (plusminus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "") + (plus:SWI (match_operator:SWI 4 "ix86_carry_flag_operator" + [(match_operand 3 "flags_reg_operand" "") + (const_int 0)]) + (match_operand:SWI 2 "" "")))) + (clobber (reg:CC FLAGS_REG))])] + "ix86_binary_operator_ok (, mode, operands)" + "") + +(define_insn "*3_carry" + [(set (match_operand:SWI 0 "nonimmediate_operand" "=m,") + (plusminus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "0,0") + (plus:SWI + (match_operator 3 "ix86_carry_flag_operator" + [(reg FLAGS_REG) (const_int 0)]) + (match_operand:SWI 2 "" ",m")))) + (clobber (reg:CC FLAGS_REG))] + "ix86_binary_operator_ok (PLUS, mode, operands)" + "{}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "use_carry" "1") + (set_attr "pent_pair" "pu") + (set_attr "mode" "")]) + +(define_insn "*addsi3_carry_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (plus:SI (match_operator 3 "ix86_carry_flag_operator" + [(reg FLAGS_REG) (const_int 0)]) + (match_operand:SI 2 "general_operand" "g"))))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT && ix86_binary_operator_ok (PLUS, SImode, operands)" + "adc{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "use_carry" "1") + (set_attr "pent_pair" "pu") + (set_attr "mode" "SI")]) + +(define_insn "*subsi3_carry_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (minus:SI (match_operand:SI 1 "register_operand" "0") + (plus:SI (match_operator 3 "ix86_carry_flag_operator" + [(reg FLAGS_REG) (const_int 0)]) + (match_operand:SI 2 "general_operand" "g"))))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT && ix86_binary_operator_ok (MINUS, SImode, operands)" + "sbb{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "pent_pair" "pu") + (set_attr "mode" "SI")]) + +;; Overflow setting add and subtract instructions + +(define_insn "*add3_cconly_overflow" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (plus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "%0") + (match_operand:SWI 2 "" "")) + (match_dup 1))) + (clobber (match_scratch:SWI 0 "="))] + "ix86_binary_operator_ok (PLUS, mode, operands)" + "add{}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "")]) +(define_insn "*sub3_cconly_overflow" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (minus:SWI + (match_operand:SWI 0 "nonimmediate_operand" "m,") + (match_operand:SWI 1 "" ",m")) + (match_dup 0)))] + "" + "cmp{}\t{%1, %0|%0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "")]) (define_insn "*3_cc_overflow" [(set (reg:CCC FLAGS_REG) @@ -8141,17 +7283,6 @@ ;; Divide instructions -(define_insn "divqi3" - [(set (match_operand:QI 0 "register_operand" "=a") - (any_div:QI - (match_operand:HI 1 "register_operand" "0") - (match_operand:QI 2 "nonimmediate_operand" "qm"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_QIMODE_MATH" - "div{b}\t%2" - [(set_attr "type" "idiv") - (set_attr "mode" "QI")]) - ;; The patterns that match these are at the end of this file. (define_expand "divxf3" @@ -8188,27 +7319,146 @@ ;; Divmod instructions. -(define_expand "divmod4" - [(parallel [(set (match_operand:SWIM248 0 "register_operand" "") - (div:SWIM248 - (match_operand:SWIM248 1 "register_operand" "") - (match_operand:SWIM248 2 "nonimmediate_operand" ""))) - (set (match_operand:SWIM248 3 "register_operand" "") - (mod:SWIM248 (match_dup 1) (match_dup 2))) +(define_expand "divmodqi4" + [(parallel [(set (match_operand:QI 0 "register_operand" "") + (div:QI + (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "nonimmediate_operand" ""))) + (set (match_operand:QI 3 "register_operand" "") + (mod:QI (match_dup 1) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] - "" - "") + "TARGET_QIMODE_MATH" +{ + rtx div, mod, insn; + rtx tmp0, tmp1; + + tmp0 = gen_reg_rtx (HImode); + tmp1 = gen_reg_rtx (HImode); -(define_insn_and_split "*divmod4" - [(set (match_operand:SWIM248 0 "register_operand" "=a") - (div:SWIM248 (match_operand:SWIM248 2 "register_operand" "0") - (match_operand:SWIM248 3 "nonimmediate_operand" "rm"))) - (set (match_operand:SWIM248 1 "register_operand" "=&d") - (mod:SWIM248 (match_dup 2) (match_dup 3))) - (clobber (reg:CC FLAGS_REG))] - "" - "#" - "&& reload_completed" + /* Extend operands[1] to HImode. Generate 8bit divide. Result is + in AX. */ + emit_insn (gen_extendqihi2 (tmp1, operands[1])); + emit_insn (gen_divmodhiqi3 (tmp0, tmp1, operands[2])); + + /* Extract remainder from AH. */ + tmp1 = gen_rtx_SIGN_EXTRACT (QImode, tmp0, GEN_INT (8), GEN_INT (8)); + insn = emit_move_insn (operands[3], tmp1); + + mod = gen_rtx_MOD (QImode, operands[1], operands[2]); + set_unique_reg_note (insn, REG_EQUAL, mod); + + /* Extract quotient from AL. */ + insn = emit_move_insn (operands[0], gen_lowpart (QImode, tmp0)); + + div = gen_rtx_DIV (QImode, operands[1], operands[2]); + set_unique_reg_note (insn, REG_EQUAL, div); + + DONE; +}) + +(define_expand "udivmodqi4" + [(parallel [(set (match_operand:QI 0 "register_operand" "") + (udiv:QI + (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "nonimmediate_operand" ""))) + (set (match_operand:QI 3 "register_operand" "") + (umod:QI (match_dup 1) (match_dup 2))) + (clobber (reg:CC FLAGS_REG))])] + "TARGET_QIMODE_MATH" +{ + rtx div, mod, insn; + rtx tmp0, tmp1; + + tmp0 = gen_reg_rtx (HImode); + tmp1 = gen_reg_rtx (HImode); + + /* Extend operands[1] to HImode. Generate 8bit divide. Result is + in AX. */ + emit_insn (gen_zero_extendqihi2 (tmp1, operands[1])); + emit_insn (gen_udivmodhiqi3 (tmp0, tmp1, operands[2])); + + /* Extract remainder from AH. */ + tmp1 = gen_rtx_ZERO_EXTRACT (SImode, tmp0, GEN_INT (8), GEN_INT (8)); + tmp1 = simplify_gen_subreg (QImode, tmp1, SImode, 0); + insn = emit_move_insn (operands[3], tmp1); + + mod = gen_rtx_UMOD (QImode, operands[1], operands[2]); + set_unique_reg_note (insn, REG_EQUAL, mod); + + /* Extract quotient from AL. */ + insn = emit_move_insn (operands[0], gen_lowpart (QImode, tmp0)); + + div = gen_rtx_UDIV (QImode, operands[1], operands[2]); + set_unique_reg_note (insn, REG_EQUAL, div); + + DONE; +}) + +;; Divide AX by r/m8, with result stored in +;; AL <- Quotient +;; AH <- Remainder +;; Change div/mod to HImode and extend the second argument to HImode +;; so that mode of div/mod matches with mode of arguments. Otherwise +;; combine may fail. +(define_insn "divmodhiqi3" + [(set (match_operand:HI 0 "register_operand" "=a") + (ior:HI + (ashift:HI + (zero_extend:HI + (truncate:QI + (mod:HI (match_operand:HI 1 "register_operand" "0") + (sign_extend:HI + (match_operand:QI 2 "nonimmediate_operand" "qm"))))) + (const_int 8)) + (zero_extend:HI + (truncate:QI + (div:HI (match_dup 1) (sign_extend:HI (match_dup 2))))))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_QIMODE_MATH" + "idiv{b}\t%2" + [(set_attr "type" "idiv") + (set_attr "mode" "QI")]) + +(define_insn "udivmodhiqi3" + [(set (match_operand:HI 0 "register_operand" "=a") + (ior:HI + (ashift:HI + (zero_extend:HI + (truncate:QI + (mod:HI (match_operand:HI 1 "register_operand" "0") + (zero_extend:HI + (match_operand:QI 2 "nonimmediate_operand" "qm"))))) + (const_int 8)) + (zero_extend:HI + (truncate:QI + (div:HI (match_dup 1) (zero_extend:HI (match_dup 2))))))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_QIMODE_MATH" + "div{b}\t%2" + [(set_attr "type" "idiv") + (set_attr "mode" "QI")]) + +(define_expand "divmod4" + [(parallel [(set (match_operand:SWIM248 0 "register_operand" "") + (div:SWIM248 + (match_operand:SWIM248 1 "register_operand" "") + (match_operand:SWIM248 2 "nonimmediate_operand" ""))) + (set (match_operand:SWIM248 3 "register_operand" "") + (mod:SWIM248 (match_dup 1) (match_dup 2))) + (clobber (reg:CC FLAGS_REG))])] + "" + "") + +(define_insn_and_split "*divmod4" + [(set (match_operand:SWIM248 0 "register_operand" "=a") + (div:SWIM248 (match_operand:SWIM248 2 "register_operand" "0") + (match_operand:SWIM248 3 "nonimmediate_operand" "rm"))) + (set (match_operand:SWIM248 1 "register_operand" "=&d") + (mod:SWIM248 (match_dup 2) (match_dup 3))) + (clobber (reg:CC FLAGS_REG))] + "" + "#" + "reload_completed" [(parallel [(set (match_dup 1) (ashiftrt:SWIM248 (match_dup 4) (match_dup 5))) (clobber (reg:CC FLAGS_REG))]) @@ -8219,7 +7469,7 @@ (use (match_dup 1)) (clobber (reg:CC FLAGS_REG))])] { - operands[5] = GEN_INT (GET_MODE_BITSIZE (mode) - 1); + operands[5] = GEN_INT (GET_MODE_BITSIZE (mode)-1); if (mode != HImode && (optimize_function_for_size_p (cfun) || TARGET_USE_CLTD)) @@ -8267,7 +7517,7 @@ (clobber (reg:CC FLAGS_REG))] "" "#" - "&& reload_completed" + "reload_completed" [(set (match_dup 1) (const_int 0)) (parallel [(set (match_dup 0) (udiv:SWIM248 (match_dup 2) (match_dup 3))) @@ -8316,39 +7566,6 @@ ;; On Pentium, "test imm, reg" is pairable only with eax, ax, and al. ;; Note that this excludes ah. -(define_insn "*testdi_1_rex64" - [(set (reg FLAGS_REG) - (compare - (and:DI (match_operand:DI 0 "nonimmediate_operand" "%!*a,r,!*a,r,rm") - (match_operand:DI 1 "x86_64_szext_general_operand" "Z,Z,e,e,re")) - (const_int 0)))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "@ - test{l}\t{%k1, %k0|%k0, %k1} - test{l}\t{%k1, %k0|%k0, %k1} - test{q}\t{%1, %0|%0, %1} - test{q}\t{%1, %0|%0, %1} - test{q}\t{%1, %0|%0, %1}" - [(set_attr "type" "test") - (set_attr "modrm" "0,1,0,1,1") - (set_attr "mode" "SI,SI,DI,DI,DI") - (set_attr "pent_pair" "uv,np,uv,np,uv")]) - -(define_insn "testsi_1" - [(set (reg FLAGS_REG) - (compare - (and:SI (match_operand:SI 0 "nonimmediate_operand" "%!*a,r,rm") - (match_operand:SI 1 "general_operand" "i,i,ri")) - (const_int 0)))] - "ix86_match_ccmode (insn, CCNOmode) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "test{l}\t{%1, %0|%0, %1}" - [(set_attr "type" "test") - (set_attr "modrm" "0,1,1") - (set_attr "mode" "SI") - (set_attr "pent_pair" "uv,np,uv")]) - (define_expand "testsi_ccno_1" [(set (reg:CCNO FLAGS_REG) (compare:CCNO @@ -8358,19 +7575,6 @@ "" "") -(define_insn "*testhi_1" - [(set (reg FLAGS_REG) - (compare (and:HI (match_operand:HI 0 "nonimmediate_operand" "%!*a,r,rm") - (match_operand:HI 1 "general_operand" "n,n,rn")) - (const_int 0)))] - "ix86_match_ccmode (insn, CCNOmode) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "test{w}\t{%1, %0|%0, %1}" - [(set_attr "type" "test") - (set_attr "modrm" "0,1,1") - (set_attr "mode" "HI") - (set_attr "pent_pair" "uv,np,uv")]) - (define_expand "testqi_ccz_1" [(set (reg:CCZ FLAGS_REG) (compare:CCZ (and:QI (match_operand:QI 0 "nonimmediate_operand" "") @@ -8379,6 +7583,25 @@ "" "") +(define_insn "*testdi_1" + [(set (reg FLAGS_REG) + (compare + (and:DI + (match_operand:DI 0 "nonimmediate_operand" "%!*a,r,!*a,r,rm") + (match_operand:DI 1 "x86_64_szext_general_operand" "Z,Z,e,e,re")) + (const_int 0)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && !(MEM_P (operands[0]) && MEM_P (operands[1]))" + "@ + test{l}\t{%k1, %k0|%k0, %k1} + test{l}\t{%k1, %k0|%k0, %k1} + test{q}\t{%1, %0|%0, %1} + test{q}\t{%1, %0|%0, %1} + test{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "test") + (set_attr "modrm" "0,1,0,1,1") + (set_attr "mode" "SI,SI,DI,DI,DI")]) + (define_insn "*testqi_1_maybe_si" [(set (reg FLAGS_REG) (compare @@ -8404,19 +7627,19 @@ (set_attr "mode" "QI,QI,QI,SI") (set_attr "pent_pair" "uv,np,uv,np")]) -(define_insn "*testqi_1" +(define_insn "*test_1" [(set (reg FLAGS_REG) - (compare - (and:QI - (match_operand:QI 0 "nonimmediate_operand" "%!*a,q,qm") - (match_operand:QI 1 "general_operand" "n,n,qn")) - (const_int 0)))] - "!(MEM_P (operands[0]) && MEM_P (operands[1])) - && ix86_match_ccmode (insn, CCNOmode)" - "test{b}\t{%1, %0|%0, %1}" + (compare + (and:SWI124 + (match_operand:SWI124 0 "nonimmediate_operand" "%!*a,,m") + (match_operand:SWI124 1 "general_operand" ",,")) + (const_int 0)))] + "ix86_match_ccmode (insn, CCNOmode) + && !(MEM_P (operands[0]) && MEM_P (operands[1]))" + "test{}\t{%1, %0|%0, %1}" [(set_attr "type" "test") (set_attr "modrm" "0,1,1") - (set_attr "mode" "QI") + (set_attr "mode" "") (set_attr "pent_pair" "uv,np,uv")]) (define_expand "testqi_ext_ccno_0" @@ -8450,7 +7673,7 @@ (set_attr "modrm" "1") (set_attr "pent_pair" "np")]) -(define_insn "*testqi_ext_1" +(define_insn "*testqi_ext_1_rex64" [(set (reg FLAGS_REG) (compare (and:SI @@ -8459,15 +7682,14 @@ (const_int 8) (const_int 8)) (zero_extend:SI - (match_operand:QI 1 "general_operand" "Qm"))) + (match_operand:QI 1 "register_operand" "Q"))) (const_int 0)))] - "!TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" "test{b}\t{%1, %h0|%h0, %1}" [(set_attr "type" "test") (set_attr "mode" "QI")]) -(define_insn "*testqi_ext_1_rex64" +(define_insn "*testqi_ext_1" [(set (reg FLAGS_REG) (compare (and:SI @@ -8476,9 +7698,9 @@ (const_int 8) (const_int 8)) (zero_extend:SI - (match_operand:QI 1 "register_operand" "Q"))) + (match_operand:QI 1 "general_operand" "Qm"))) (const_int 0)))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" + "!TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" "test{b}\t{%1, %h0|%h0, %1}" [(set_attr "type" "test") (set_attr "mode" "QI")]) @@ -8501,24 +7723,6 @@ [(set_attr "type" "test") (set_attr "mode" "QI")]) -;; Combine likes to form bit extractions for some tests. Humor it. -(define_insn "*testqi_ext_3" - [(set (reg FLAGS_REG) - (compare (zero_extract:SI - (match_operand 0 "nonimmediate_operand" "rm") - (match_operand:SI 1 "const_int_operand" "") - (match_operand:SI 2 "const_int_operand" "")) - (const_int 0)))] - "ix86_match_ccmode (insn, CCNOmode) - && INTVAL (operands[1]) > 0 - && INTVAL (operands[2]) >= 0 - && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32 - && (GET_MODE (operands[0]) == SImode - || (TARGET_64BIT && GET_MODE (operands[0]) == DImode) - || GET_MODE (operands[0]) == HImode - || GET_MODE (operands[0]) == QImode)" - "#") - (define_insn "*testqi_ext_3_rex64" [(set (reg FLAGS_REG) (compare (zero_extract:DI @@ -8540,6 +7744,24 @@ || GET_MODE (operands[0]) == QImode)" "#") +;; Combine likes to form bit extractions for some tests. Humor it. +(define_insn "*testqi_ext_3" + [(set (reg FLAGS_REG) + (compare (zero_extract:SI + (match_operand 0 "nonimmediate_operand" "rm") + (match_operand:SI 1 "const_int_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (const_int 0)))] + "ix86_match_ccmode (insn, CCNOmode) + && INTVAL (operands[1]) > 0 + && INTVAL (operands[2]) >= 0 + && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32 + && (GET_MODE (operands[0]) == SImode + || (TARGET_64BIT && GET_MODE (operands[0]) == DImode) + || GET_MODE (operands[0]) == HImode + || GET_MODE (operands[0]) == QImode)" + "#") + (define_split [(set (match_operand 0 "flags_reg_operand" "") (match_operator 1 "compare_operator" @@ -8639,22 +7861,22 @@ "operands[2] = gen_lowpart (QImode, operands[2]); operands[3] = gen_lowpart (QImode, operands[3]);") - ;; %%% This used to optimize known byte-wide and operations to memory, ;; and sometimes to QImode registers. If this is considered useful, ;; it should be done with splitters. -(define_expand "anddi3" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (and:DI (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:DI 2 "x86_64_szext_general_operand" "")))] - "TARGET_64BIT" - "ix86_expand_binary_operator (AND, DImode, operands); DONE;") +(define_expand "and3" + [(set (match_operand:SWIM 0 "nonimmediate_operand" "") + (and:SWIM (match_operand:SWIM 1 "nonimmediate_operand" "") + (match_operand:SWIM 2 "" "")))] + "" + "ix86_expand_binary_operator (AND, mode, operands); DONE;") -(define_insn "*anddi_1_rex64" +(define_insn "*anddi_1" [(set (match_operand:DI 0 "nonimmediate_operand" "=r,rm,r,r") - (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0,qm") - (match_operand:DI 2 "x86_64_szext_general_operand" "Z,re,rm,L"))) + (and:DI + (match_operand:DI 1 "nonimmediate_operand" "%0,0,0,qm") + (match_operand:DI 2 "x86_64_szext_general_operand" "Z,re,rm,L"))) (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT && ix86_binary_operator_ok (AND, DImode, operands)" { @@ -8699,29 +7921,6 @@ (const_string "*"))) (set_attr "mode" "SI,DI,DI,SI")]) -(define_insn "*anddi_2" - [(set (reg FLAGS_REG) - (compare (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:DI 2 "x86_64_szext_general_operand" "Z,rem,re")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=r,r,rm") - (and:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (AND, DImode, operands)" - "@ - and{l}\t{%k2, %k0|%k0, %k2} - and{q}\t{%2, %0|%0, %2} - and{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI,DI,DI")]) - -(define_expand "andsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (and:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:SI 2 "general_operand" "")))] - "" - "ix86_expand_binary_operator (AND, SImode, operands); DONE;") - (define_insn "*andsi_1" [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r,r") (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,qm") @@ -8767,43 +7966,6 @@ (set_attr "length_immediate" "*,*,0") (set_attr "mode" "SI")]) -(define_split - [(set (match_operand 0 "register_operand" "") - (and (match_dup 0) - (const_int -65536))) - (clobber (reg:CC FLAGS_REG))] - "optimize_function_for_size_p (cfun) || (TARGET_FAST_PREFIX && !TARGET_PARTIAL_REG_STALL)" - [(set (strict_low_part (match_dup 1)) (const_int 0))] - "operands[1] = gen_lowpart (HImode, operands[0]);") - -(define_split - [(set (match_operand 0 "ext_register_operand" "") - (and (match_dup 0) - (const_int -256))) - (clobber (reg:CC FLAGS_REG))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_REG_STALL) && reload_completed" - [(set (strict_low_part (match_dup 1)) (const_int 0))] - "operands[1] = gen_lowpart (QImode, operands[0]);") - -(define_split - [(set (match_operand 0 "ext_register_operand" "") - (and (match_dup 0) - (const_int -65281))) - (clobber (reg:CC FLAGS_REG))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_REG_STALL) && reload_completed" - [(parallel [(set (zero_extract:SI (match_dup 0) - (const_int 8) - (const_int 8)) - (xor:SI - (zero_extract:SI (match_dup 0) - (const_int 8) - (const_int 8)) - (zero_extract:SI (match_dup 0) - (const_int 8) - (const_int 8)))) - (clobber (reg:CC FLAGS_REG))])] - "operands[0] = gen_lowpart (SImode, operands[0]);") - ;; See comment for addsi_1_zext why we do use nonimmediate_operand (define_insn "*andsi_1_zext" [(set (match_operand:DI 0 "register_operand" "=r") @@ -8816,40 +7978,6 @@ [(set_attr "type" "alu") (set_attr "mode" "SI")]) -(define_insn "*andsi_2" - [(set (reg FLAGS_REG) - (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "g,ri")) - (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm") - (and:SI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (AND, SImode, operands)" - "and{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) - -;; See comment for addsi_1_zext why we do use nonimmediate_operand -(define_insn "*andsi_2_zext" - [(set (reg FLAGS_REG) - (compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0") - (match_operand:SI 2 "general_operand" "g")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (and:SI (match_dup 1) (match_dup 2))))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (AND, SImode, operands)" - "and{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) - -(define_expand "andhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (and:HI (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_binary_operator (AND, HImode, operands); DONE;") - (define_insn "*andhi_1" [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r") (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,qm") @@ -8880,26 +8008,6 @@ (const_string "*"))) (set_attr "mode" "HI,HI,SI")]) -(define_insn "*andhi_2" - [(set (reg FLAGS_REG) - (compare (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") - (match_operand:HI 2 "general_operand" "rmn,rn")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") - (and:HI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (AND, HImode, operands)" - "and{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "HI")]) - -(define_expand "andqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (and:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "general_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_binary_operator (AND, QImode, operands); DONE;") - ;; %%% Potential partial reg stall on alternative 2. What to do? (define_insn "*andqi_1" [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r") @@ -8919,20 +8027,78 @@ (and:QI (match_dup 0) (match_operand:QI 1 "general_operand" "qn,qmn"))) (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) + "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) && !(MEM_P (operands[0]) && MEM_P (operands[1]))" "and{b}\t{%1, %0|%0, %1}" [(set_attr "type" "alu1") (set_attr "mode" "QI")]) -(define_insn "*andqi_2_maybe_si" - [(set (reg FLAGS_REG) - (compare (and:QI - (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:QI 2 "general_operand" "qmn,qn,n")) - (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm,*r") - (and:QI (match_dup 1) (match_dup 2)))] +(define_split + [(set (match_operand 0 "register_operand" "") + (and (match_dup 0) + (const_int -65536))) + (clobber (reg:CC FLAGS_REG))] + "(TARGET_FAST_PREFIX && !TARGET_PARTIAL_REG_STALL) + || optimize_function_for_size_p (cfun)" + [(set (strict_low_part (match_dup 1)) (const_int 0))] + "operands[1] = gen_lowpart (HImode, operands[0]);") + +(define_split + [(set (match_operand 0 "ext_register_operand" "") + (and (match_dup 0) + (const_int -256))) + (clobber (reg:CC FLAGS_REG))] + "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) + && reload_completed" + [(set (strict_low_part (match_dup 1)) (const_int 0))] + "operands[1] = gen_lowpart (QImode, operands[0]);") + +(define_split + [(set (match_operand 0 "ext_register_operand" "") + (and (match_dup 0) + (const_int -65281))) + (clobber (reg:CC FLAGS_REG))] + "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) + && reload_completed" + [(parallel [(set (zero_extract:SI (match_dup 0) + (const_int 8) + (const_int 8)) + (xor:SI + (zero_extract:SI (match_dup 0) + (const_int 8) + (const_int 8)) + (zero_extract:SI (match_dup 0) + (const_int 8) + (const_int 8)))) + (clobber (reg:CC FLAGS_REG))])] + "operands[0] = gen_lowpart (SImode, operands[0]);") + +(define_insn "*anddi_2" + [(set (reg FLAGS_REG) + (compare + (and:DI + (match_operand:DI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:DI 2 "x86_64_szext_general_operand" "Z,rem,re")) + (const_int 0))) + (set (match_operand:DI 0 "nonimmediate_operand" "=r,r,rm") + (and:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (AND, DImode, operands)" + "@ + and{l}\t{%k2, %k0|%k0, %k2} + and{q}\t{%2, %0|%0, %2} + and{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI,DI,DI")]) + +(define_insn "*andqi_2_maybe_si" + [(set (reg FLAGS_REG) + (compare (and:QI + (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:QI 2 "general_operand" "qmn,qn,n")) + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm,*r") + (and:QI (match_dup 1) (match_dup 2)))] "ix86_binary_operator_ok (AND, QImode, operands) && ix86_match_ccmode (insn, CONST_INT_P (operands[2]) @@ -8949,19 +8115,34 @@ [(set_attr "type" "alu") (set_attr "mode" "QI,QI,SI")]) -(define_insn "*andqi_2" +(define_insn "*and_2" [(set (reg FLAGS_REG) - (compare (and:QI - (match_operand:QI 1 "nonimmediate_operand" "%0,0") - (match_operand:QI 2 "general_operand" "qmn,qn")) + (compare (and:SWI124 + (match_operand:SWI124 1 "nonimmediate_operand" "%0,0") + (match_operand:SWI124 2 "general_operand" ",")) (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm") - (and:QI (match_dup 1) (match_dup 2)))] + (set (match_operand:SWI124 0 "nonimmediate_operand" "=,m") + (and:SWI124 (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (AND, QImode, operands)" - "and{b}\t{%2, %0|%0, %2}" + && ix86_binary_operator_ok (AND, mode, operands)" + "and{}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") - (set_attr "mode" "QI")]) + (set_attr "mode" "")]) + +;; See comment for addsi_1_zext why we do use nonimmediate_operand +(define_insn "*andsi_2_zext" + [(set (reg FLAGS_REG) + (compare (and:SI + (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "g")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (and:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && ix86_binary_operator_ok (AND, SImode, operands)" + "and{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) (define_insn "*andqi_2_slp" [(set (reg FLAGS_REG) @@ -8971,7 +8152,7 @@ (const_int 0))) (set (strict_low_part (match_dup 0)) (and:QI (match_dup 0) (match_dup 1)))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) + "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) && ix86_match_ccmode (insn, CCNOmode) && !(MEM_P (operands[0]) && MEM_P (operands[1]))" "and{b}\t{%1, %0|%0, %1}" @@ -8981,7 +8162,6 @@ ;; ??? A bug in recog prevents it from recognizing a const_int as an ;; operand to zero_extend in andqi_ext_1. It was checking explicitly ;; for a QImode operand, which of course failed. - (define_insn "andqi_ext_0" [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") (const_int 8) @@ -9002,7 +8182,6 @@ ;; Generated by peephole translating test to and. This shows up ;; often in fp comparisons. - (define_insn "*andqi_ext_0_cc" [(set (reg FLAGS_REG) (compare @@ -9029,7 +8208,7 @@ (set_attr "modrm" "1") (set_attr "mode" "QI")]) -(define_insn "*andqi_ext_1" +(define_insn "*andqi_ext_1_rex64" [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") (const_int 8) (const_int 8)) @@ -9039,15 +8218,15 @@ (const_int 8) (const_int 8)) (zero_extend:SI - (match_operand:QI 2 "general_operand" "Qm")))) + (match_operand 2 "ext_register_operand" "Q")))) (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT" + "TARGET_64BIT" "and{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") (set_attr "length_immediate" "0") (set_attr "mode" "QI")]) -(define_insn "*andqi_ext_1_rex64" +(define_insn "*andqi_ext_1" [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") (const_int 8) (const_int 8)) @@ -9057,9 +8236,9 @@ (const_int 8) (const_int 8)) (zero_extend:SI - (match_operand 2 "ext_register_operand" "Q")))) + (match_operand:QI 2 "general_operand" "Qm")))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" + "!TARGET_64BIT" "and{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") (set_attr "length_immediate" "0") @@ -9130,323 +8309,208 @@ operands[1] = gen_lowpart (QImode, operands[1]); operands[2] = gen_lowpart (QImode, operands[2]);") -;; Logical inclusive OR instructions +;; Logical inclusive and exclusive OR instructions ;; %%% This used to optimize known byte-wide and operations to memory. ;; If this is considered useful, it should be done with splitters. -(define_expand "iordi3" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (ior:DI (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:DI 2 "x86_64_general_operand" "")))] - "TARGET_64BIT" - "ix86_expand_binary_operator (IOR, DImode, operands); DONE;") +(define_expand "3" + [(set (match_operand:SWIM 0 "nonimmediate_operand" "") + (any_or:SWIM (match_operand:SWIM 1 "nonimmediate_operand" "") + (match_operand:SWIM 2 "" "")))] + "" + "ix86_expand_binary_operator (, mode, operands); DONE;") -(define_insn "*iordi_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") - (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") - (match_operand:DI 2 "x86_64_general_operand" "re,rme"))) +(define_insn "*_1" + [(set (match_operand:SWI248 0 "nonimmediate_operand" "=r,rm") + (any_or:SWI248 + (match_operand:SWI248 1 "nonimmediate_operand" "%0,0") + (match_operand:SWI248 2 "" ",r"))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && ix86_binary_operator_ok (IOR, DImode, operands)" - "or{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "DI")]) - -(define_insn "*iordi_2_rex64" - [(set (reg FLAGS_REG) - (compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") - (match_operand:DI 2 "x86_64_general_operand" "rem,re")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=r,rm") - (ior:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT - && ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (IOR, DImode, operands)" - "or{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "DI")]) - -(define_insn "*iordi_3_rex64" - [(set (reg FLAGS_REG) - (compare (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0") - (match_operand:DI 2 "x86_64_general_operand" "rem")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT - && ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (IOR, DImode, operands)" - "or{q}\t{%2, %0|%0, %2}" + "ix86_binary_operator_ok (, mode, operands)" + "{}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") - (set_attr "mode" "DI")]) - - -(define_expand "iorsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (ior:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:SI 2 "general_operand" "")))] - "" - "ix86_expand_binary_operator (IOR, SImode, operands); DONE;") + (set_attr "mode" "")]) -(define_insn "*iorsi_1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") - (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "ri,g"))) +;; %%% Potential partial reg stall on alternative 2. What to do? +(define_insn "*qi_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,r") + (any_or:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:QI 2 "general_operand" "qmn,qn,rn"))) (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (IOR, SImode, operands)" - "or{l}\t{%2, %0|%0, %2}" + "ix86_binary_operator_ok (, QImode, operands)" + "@ + {b}\t{%2, %0|%0, %2} + {b}\t{%2, %0|%0, %2} + {l}\t{%k2, %k0|%k0, %k2}" [(set_attr "type" "alu") - (set_attr "mode" "SI")]) + (set_attr "mode" "QI,QI,SI")]) ;; See comment for addsi_1_zext why we do use nonimmediate_operand -(define_insn "*iorsi_1_zext" +(define_insn "*si_1_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI - (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") - (match_operand:SI 2 "general_operand" "g")))) + (any_or:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "g")))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (IOR, SImode, operands)" - "or{l}\t{%2, %k0|%k0, %2}" + "TARGET_64BIT && ix86_binary_operator_ok (, SImode, operands)" + "{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") (set_attr "mode" "SI")]) -(define_insn "*iorsi_1_zext_imm" +(define_insn "*si_1_zext_imm" [(set (match_operand:DI 0 "register_operand" "=r") - (ior:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) - (match_operand:DI 2 "x86_64_zext_immediate_operand" "Z"))) + (any_or:DI + (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) + (match_operand:DI 2 "x86_64_zext_immediate_operand" "Z"))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "or{l}\t{%2, %k0|%k0, %2}" + "TARGET_64BIT && ix86_binary_operator_ok (, SImode, operands)" + "{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") (set_attr "mode" "SI")]) -(define_insn "*iorsi_2" +(define_insn "*qi_1_slp" + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+q,m")) + (any_or:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "qmn,qn"))) + (clobber (reg:CC FLAGS_REG))] + "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) + && !(MEM_P (operands[0]) && MEM_P (operands[1]))" + "{b}\t{%1, %0|%0, %1}" + [(set_attr "type" "alu1") + (set_attr "mode" "QI")]) + +(define_insn "*_2" [(set (reg FLAGS_REG) - (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "g,ri")) + (compare (any_or:SWI + (match_operand:SWI 1 "nonimmediate_operand" "%0,0") + (match_operand:SWI 2 "" ",")) (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm") - (ior:SI (match_dup 1) (match_dup 2)))] + (set (match_operand:SWI 0 "nonimmediate_operand" "=,m") + (any_or:SWI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (IOR, SImode, operands)" - "or{l}\t{%2, %0|%0, %2}" + && ix86_binary_operator_ok (, mode, operands)" + "{}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) ;; See comment for addsi_1_zext why we do use nonimmediate_operand ;; ??? Special case for immediate operand is missing - it is tricky. -(define_insn "*iorsi_2_zext" +(define_insn "*si_2_zext" [(set (reg FLAGS_REG) - (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") - (match_operand:SI 2 "general_operand" "g")) + (compare (any_or:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "g")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (ior:SI (match_dup 1) (match_dup 2))))] + (zero_extend:DI (any_or:SI (match_dup 1) (match_dup 2))))] "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (IOR, SImode, operands)" - "or{l}\t{%2, %k0|%k0, %2}" + && ix86_binary_operator_ok (, SImode, operands)" + "{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") (set_attr "mode" "SI")]) -(define_insn "*iorsi_2_zext_imm" +(define_insn "*si_2_zext_imm" [(set (reg FLAGS_REG) - (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") - (match_operand 2 "x86_64_zext_immediate_operand" "Z")) + (compare (any_or:SI + (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "x86_64_zext_immediate_operand" "Z")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") - (ior:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))] + (any_or:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))] "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (IOR, SImode, operands)" - "or{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) - -(define_insn "*iorsi_3" - [(set (reg FLAGS_REG) - (compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") - (match_operand:SI 2 "general_operand" "g")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "ix86_match_ccmode (insn, CCNOmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "or{l}\t{%2, %0|%0, %2}" + && ix86_binary_operator_ok (, SImode, operands)" + "{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") (set_attr "mode" "SI")]) -(define_expand "iorhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (ior:HI (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_binary_operator (IOR, HImode, operands); DONE;") - -(define_insn "*iorhi_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=r,m") - (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") - (match_operand:HI 2 "general_operand" "rmn,rn"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (IOR, HImode, operands)" - "or{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "HI")]) - -(define_insn "*iorhi_2" - [(set (reg FLAGS_REG) - (compare (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") - (match_operand:HI 2 "general_operand" "rmn,rn")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") - (ior:HI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (IOR, HImode, operands)" - "or{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "HI")]) - -(define_insn "*iorhi_3" - [(set (reg FLAGS_REG) - (compare (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0") - (match_operand:HI 2 "general_operand" "rmn")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "ix86_match_ccmode (insn, CCNOmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "or{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "HI")]) - -(define_expand "iorqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (ior:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "general_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_binary_operator (IOR, QImode, operands); DONE;") - -;; %%% Potential partial reg stall on alternative 2. What to do? -(define_insn "*iorqi_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,r") - (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:QI 2 "general_operand" "qmn,qn,rn"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (IOR, QImode, operands)" - "@ - or{b}\t{%2, %0|%0, %2} - or{b}\t{%2, %0|%0, %2} - or{l}\t{%k2, %k0|%k0, %k2}" - [(set_attr "type" "alu") - (set_attr "mode" "QI,QI,SI")]) - -(define_insn "*iorqi_1_slp" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+q,m")) - (ior:QI (match_dup 0) - (match_operand:QI 1 "general_operand" "qmn,qn"))) - (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "or{b}\t{%1, %0|%0, %1}" - [(set_attr "type" "alu1") - (set_attr "mode" "QI")]) - -(define_insn "*iorqi_2" - [(set (reg FLAGS_REG) - (compare (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") - (match_operand:QI 2 "general_operand" "qmn,qn")) - (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm") - (ior:QI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (IOR, QImode, operands)" - "or{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "QI")]) - -(define_insn "*iorqi_2_slp" +(define_insn "*qi_2_slp" [(set (reg FLAGS_REG) - (compare (ior:QI (match_operand:QI 0 "nonimmediate_operand" "+q,qm") - (match_operand:QI 1 "general_operand" "qmn,qn")) + (compare (any_or:QI (match_operand:QI 0 "nonimmediate_operand" "+q,qm") + (match_operand:QI 1 "general_operand" "qmn,qn")) (const_int 0))) (set (strict_low_part (match_dup 0)) - (ior:QI (match_dup 0) (match_dup 1)))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) + (any_or:QI (match_dup 0) (match_dup 1)))] + "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) && ix86_match_ccmode (insn, CCNOmode) && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "or{b}\t{%1, %0|%0, %1}" + "{b}\t{%1, %0|%0, %1}" [(set_attr "type" "alu1") (set_attr "mode" "QI")]) -(define_insn "*iorqi_3" +(define_insn "*_3" [(set (reg FLAGS_REG) - (compare (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0") - (match_operand:QI 2 "general_operand" "qmn")) + (compare (any_or:SWI + (match_operand:SWI 1 "nonimmediate_operand" "%0") + (match_operand:SWI 2 "" "")) (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] + (clobber (match_scratch:SWI 0 "="))] "ix86_match_ccmode (insn, CCNOmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "or{b}\t{%2, %0|%0, %2}" + && ix86_binary_operator_ok (, mode, operands)" + "{}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") - (set_attr "mode" "QI")]) + (set_attr "mode" "")]) -(define_insn "*iorqi_ext_0" +(define_insn "*qi_ext_0" [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") (const_int 8) (const_int 8)) - (ior:SI + (any_or:SI (zero_extract:SI (match_operand 1 "ext_register_operand" "0") (const_int 8) (const_int 8)) (match_operand 2 "const_int_operand" "n"))) (clobber (reg:CC FLAGS_REG))] - "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))" - "or{b}\t{%2, %h0|%h0, %2}" + "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" + "{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") (set_attr "length_immediate" "1") (set_attr "modrm" "1") (set_attr "mode" "QI")]) -(define_insn "*iorqi_ext_1" +(define_insn "*qi_ext_1_rex64" [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") (const_int 8) (const_int 8)) - (ior:SI + (any_or:SI (zero_extract:SI (match_operand 1 "ext_register_operand" "0") (const_int 8) (const_int 8)) (zero_extend:SI - (match_operand:QI 2 "general_operand" "Qm")))) + (match_operand 2 "ext_register_operand" "Q")))) (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT + "TARGET_64BIT && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))" - "or{b}\t{%2, %h0|%h0, %2}" + "{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") (set_attr "length_immediate" "0") (set_attr "mode" "QI")]) -(define_insn "*iorqi_ext_1_rex64" +(define_insn "*qi_ext_1" [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") (const_int 8) (const_int 8)) - (ior:SI + (any_or:SI (zero_extract:SI (match_operand 1 "ext_register_operand" "0") (const_int 8) (const_int 8)) (zero_extend:SI - (match_operand 2 "ext_register_operand" "Q")))) + (match_operand:QI 2 "general_operand" "Qm")))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT + "!TARGET_64BIT && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))" - "or{b}\t{%2, %h0|%h0, %2}" + "{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") (set_attr "length_immediate" "0") (set_attr "mode" "QI")]) -(define_insn "*iorqi_ext_2" +(define_insn "*qi_ext_2" [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") (const_int 8) (const_int 8)) - (ior:SI + (any_or:SI (zero_extract:SI (match_operand 1 "ext_register_operand" "0") (const_int 8) (const_int 8)) @@ -9454,16 +8518,16 @@ (const_int 8) (const_int 8)))) (clobber (reg:CC FLAGS_REG))] - "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))" - "ior{b}\t{%h2, %h0|%h0, %h2}" + "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" + "{b}\t{%h2, %h0|%h0, %h2}" [(set_attr "type" "alu") (set_attr "length_immediate" "0") (set_attr "mode" "QI")]) (define_split [(set (match_operand 0 "register_operand" "") - (ior (match_operand 1 "register_operand" "") - (match_operand 2 "const_int_operand" ""))) + (any_or (match_operand 1 "register_operand" "") + (match_operand 2 "const_int_operand" ""))) (clobber (reg:CC FLAGS_REG))] "reload_completed && QI_REG_P (operands[0]) @@ -9471,9 +8535,9 @@ && !(INTVAL (operands[2]) & ~(255 << 8)) && GET_MODE (operands[0]) != QImode" [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 8) (const_int 8)) - (ior:SI (zero_extract:SI (match_dup 1) - (const_int 8) (const_int 8)) - (match_dup 2))) + (any_or:SI (zero_extract:SI (match_dup 1) + (const_int 8) (const_int 8)) + (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] "operands[0] = gen_lowpart (SImode, operands[0]); operands[1] = gen_lowpart (SImode, operands[1]); @@ -9483,8 +8547,8 @@ ;; profitable when 7th bit is set. (define_split [(set (match_operand 0 "register_operand" "") - (ior (match_operand 1 "general_operand" "") - (match_operand 2 "const_int_operand" ""))) + (any_or (match_operand 1 "general_operand" "") + (match_operand 2 "const_int_operand" ""))) (clobber (reg:CC FLAGS_REG))] "reload_completed && ANY_QI_REG_P (operands[0]) @@ -9493,4047 +8557,1750 @@ && (INTVAL (operands[2]) & 128) && GET_MODE (operands[0]) != QImode" [(parallel [(set (strict_low_part (match_dup 0)) - (ior:QI (match_dup 1) - (match_dup 2))) + (any_or:QI (match_dup 1) + (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] "operands[0] = gen_lowpart (QImode, operands[0]); operands[1] = gen_lowpart (QImode, operands[1]); operands[2] = gen_lowpart (QImode, operands[2]);") - -;; Logical XOR instructions - -;; %%% This used to optimize known byte-wide and operations to memory. -;; If this is considered useful, it should be done with splitters. - -(define_expand "xordi3" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (xor:DI (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:DI 2 "x86_64_general_operand" "")))] - "TARGET_64BIT" - "ix86_expand_binary_operator (XOR, DImode, operands); DONE;") -(define_insn "*xordi_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") - (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") - (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && ix86_binary_operator_ok (XOR, DImode, operands)" - "xor{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "DI")]) +(define_expand "xorqi_cc_ext_1" + [(parallel [ + (set (reg:CCNO FLAGS_REG) + (compare:CCNO + (xor:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "") + (const_int 8) + (const_int 8)) + (match_operand:QI 2 "general_operand" "")) + (const_int 0))) + (set (zero_extract:SI (match_operand 0 "ext_register_operand" "") + (const_int 8) + (const_int 8)) + (xor:SI + (zero_extract:SI + (match_dup 1) + (const_int 8) + (const_int 8)) + (match_dup 2)))])] + "" + "") -(define_insn "*xordi_2_rex64" +(define_insn "*xorqi_cc_ext_1_rex64" [(set (reg FLAGS_REG) - (compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") - (match_operand:DI 2 "x86_64_general_operand" "rem,re")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=r,rm") - (xor:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT - && ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (XOR, DImode, operands)" - "xor{q}\t{%2, %0|%0, %2}" + (compare + (xor:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (match_operand:QI 2 "nonmemory_operand" "Qn")) + (const_int 0))) + (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (xor:SI + (zero_extract:SI + (match_dup 1) + (const_int 8) + (const_int 8)) + (match_dup 2)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" + "xor{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") - (set_attr "mode" "DI")]) + (set_attr "modrm" "1") + (set_attr "mode" "QI")]) -(define_insn "*xordi_3_rex64" +(define_insn "*xorqi_cc_ext_1" [(set (reg FLAGS_REG) - (compare (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0") - (match_operand:DI 2 "x86_64_general_operand" "rem")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT - && ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (XOR, DImode, operands)" - "xor{q}\t{%2, %0|%0, %2}" + (compare + (xor:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (match_operand:QI 2 "general_operand" "qmn")) + (const_int 0))) + (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q") + (const_int 8) + (const_int 8)) + (xor:SI + (zero_extract:SI + (match_dup 1) + (const_int 8) + (const_int 8)) + (match_dup 2)))] + "!TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" + "xor{b}\t{%2, %h0|%h0, %2}" [(set_attr "type" "alu") - (set_attr "mode" "DI")]) + (set_attr "modrm" "1") + (set_attr "mode" "QI")]) + +;; Negation instructions -(define_expand "xorsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (xor:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:SI 2 "general_operand" "")))] +(define_expand "neg2" + [(set (match_operand:SDWIM 0 "nonimmediate_operand" "") + (neg:SDWIM (match_operand:SDWIM 1 "nonimmediate_operand" "")))] "" - "ix86_expand_binary_operator (XOR, SImode, operands); DONE;") + "ix86_expand_unary_operator (NEG, mode, operands); DONE;") -(define_insn "*xorsi_1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") - (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "ri,rm"))) +(define_insn_and_split "*neg2_doubleword" + [(set (match_operand: 0 "nonimmediate_operand" "=ro") + (neg: (match_operand: 1 "nonimmediate_operand" "0"))) (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (XOR, SImode, operands)" - "xor{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) + "ix86_unary_operator_ok (NEG, mode, operands)" + "#" + "reload_completed" + [(parallel + [(set (reg:CCZ FLAGS_REG) + (compare:CCZ (neg:DWIH (match_dup 1)) (const_int 0))) + (set (match_dup 0) (neg:DWIH (match_dup 1)))]) + (parallel + [(set (match_dup 2) + (plus:DWIH (match_dup 3) + (plus:DWIH (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0)) + (const_int 0)))) + (clobber (reg:CC FLAGS_REG))]) + (parallel + [(set (match_dup 2) + (neg:DWIH (match_dup 2))) + (clobber (reg:CC FLAGS_REG))])] + "split_ (&operands[0], 2, &operands[0], &operands[2]);") -;; See comment for addsi_1_zext why we do use nonimmediate_operand -;; Add speccase for immediates -(define_insn "*xorsi_1_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") - (match_operand:SI 2 "general_operand" "g")))) +(define_insn "*neg2_1" + [(set (match_operand:SWI 0 "nonimmediate_operand" "=m") + (neg:SWI (match_operand:SWI 1 "nonimmediate_operand" "0"))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (XOR, SImode, operands)" - "xor{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) + "ix86_unary_operator_ok (NEG, mode, operands)" + "neg{}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "")]) -(define_insn "*xorsi_1_zext_imm" +;; Combine is quite creative about this pattern. +(define_insn "*negsi2_1_zext" [(set (match_operand:DI 0 "register_operand" "=r") - (xor:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0")) - (match_operand:DI 2 "x86_64_zext_immediate_operand" "Z"))) + (lshiftrt:DI + (neg:DI (ashift:DI (match_operand:DI 1 "register_operand" "0") + (const_int 32))) + (const_int 32))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (XOR, SImode, operands)" - "xor{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "alu") + "TARGET_64BIT && ix86_unary_operator_ok (NEG, SImode, operands)" + "neg{l}\t%k0" + [(set_attr "type" "negnot") (set_attr "mode" "SI")]) -(define_insn "*xorsi_2" - [(set (reg FLAGS_REG) - (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "g,ri")) - (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm") - (xor:SI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (XOR, SImode, operands)" - "xor{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) +;; The problem with neg is that it does not perform (compare x 0), +;; it really performs (compare 0 x), which leaves us with the zero +;; flag being the only useful item. -;; See comment for addsi_1_zext why we do use nonimmediate_operand -;; ??? Special case for immediate operand is missing - it is tricky. -(define_insn "*xorsi_2_zext" - [(set (reg FLAGS_REG) - (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") - (match_operand:SI 2 "general_operand" "g")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (xor:SI (match_dup 1) (match_dup 2))))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (XOR, SImode, operands)" - "xor{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) +(define_insn "*neg2_cmpz" + [(set (reg:CCZ FLAGS_REG) + (compare:CCZ + (neg:SWI (match_operand:SWI 1 "nonimmediate_operand" "0")) + (const_int 0))) + (set (match_operand:SWI 0 "nonimmediate_operand" "=m") + (neg:SWI (match_dup 1)))] + "ix86_unary_operator_ok (NEG, mode, operands)" + "neg{}\t%0" + [(set_attr "type" "negnot") + (set_attr "mode" "")]) -(define_insn "*xorsi_2_zext_imm" - [(set (reg FLAGS_REG) - (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") - (match_operand 2 "x86_64_zext_immediate_operand" "Z")) - (const_int 0))) +(define_insn "*negsi2_cmpz_zext" + [(set (reg:CCZ FLAGS_REG) + (compare:CCZ + (lshiftrt:DI + (neg:DI (ashift:DI + (match_operand:DI 1 "register_operand" "0") + (const_int 32))) + (const_int 32)) + (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") - (xor:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (XOR, SImode, operands)" - "xor{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "alu") + (lshiftrt:DI (neg:DI (ashift:DI (match_dup 1) + (const_int 32))) + (const_int 32)))] + "TARGET_64BIT && ix86_unary_operator_ok (NEG, SImode, operands)" + "neg{l}\t%k0" + [(set_attr "type" "negnot") (set_attr "mode" "SI")]) -(define_insn "*xorsi_3" - [(set (reg FLAGS_REG) - (compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") - (match_operand:SI 2 "general_operand" "g")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "ix86_match_ccmode (insn, CCNOmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "xor{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) +;; Changing of sign for FP values is doable using integer unit too. -(define_expand "xorhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (xor:HI (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_binary_operator (XOR, HImode, operands); DONE;") - -(define_insn "*xorhi_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=r,m") - (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") - (match_operand:HI 2 "general_operand" "rmn,rn"))) +(define_expand "2" + [(set (match_operand:X87MODEF 0 "register_operand" "") + (absneg:X87MODEF (match_operand:X87MODEF 1 "register_operand" "")))] + "TARGET_80387 || (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)" + "ix86_expand_fp_absneg_operator (, mode, operands); DONE;") + +(define_insn "*absneg2_mixed" + [(set (match_operand:MODEF 0 "register_operand" "=x,x,f,!r") + (match_operator:MODEF 3 "absneg_operator" + [(match_operand:MODEF 1 "register_operand" "0,x,0,0")])) + (use (match_operand: 2 "nonimmediate_operand" "xm,0,X,X")) (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (XOR, HImode, operands)" - "xor{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "HI")]) + "TARGET_MIX_SSE_I387 && SSE_FLOAT_MODE_P (mode)" + "#") -(define_insn "*xorhi_2" - [(set (reg FLAGS_REG) - (compare (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") - (match_operand:HI 2 "general_operand" "rmn,rn")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") - (xor:HI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (XOR, HImode, operands)" - "xor{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "HI")]) +(define_insn "*absneg2_sse" + [(set (match_operand:MODEF 0 "register_operand" "=x,x,!r") + (match_operator:MODEF 3 "absneg_operator" + [(match_operand:MODEF 1 "register_operand" "0 ,x,0")])) + (use (match_operand: 2 "register_operand" "xm,0,X")) + (clobber (reg:CC FLAGS_REG))] + "SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH" + "#") -(define_insn "*xorhi_3" - [(set (reg FLAGS_REG) - (compare (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0") - (match_operand:HI 2 "general_operand" "rmn")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "ix86_match_ccmode (insn, CCNOmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "xor{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "HI")]) +(define_insn "*absneg2_i387" + [(set (match_operand:X87MODEF 0 "register_operand" "=f,!r") + (match_operator:X87MODEF 3 "absneg_operator" + [(match_operand:X87MODEF 1 "register_operand" "0,0")])) + (use (match_operand 2 "" "")) + (clobber (reg:CC FLAGS_REG))] + "TARGET_80387 && !(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)" + "#") -(define_expand "xorqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (xor:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "general_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_binary_operator (XOR, QImode, operands); DONE;") +(define_expand "tf2" + [(set (match_operand:TF 0 "register_operand" "") + (absneg:TF (match_operand:TF 1 "register_operand" "")))] + "TARGET_SSE2" + "ix86_expand_fp_absneg_operator (, TFmode, operands); DONE;") -;; %%% Potential partial reg stall on alternative 2. What to do? -(define_insn "*xorqi_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,r") - (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:QI 2 "general_operand" "qmn,qn,rn"))) +(define_insn "*absnegtf2_sse" + [(set (match_operand:TF 0 "register_operand" "=x,x") + (match_operator:TF 3 "absneg_operator" + [(match_operand:TF 1 "register_operand" "0,x")])) + (use (match_operand:TF 2 "nonimmediate_operand" "xm,0")) (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (XOR, QImode, operands)" - "@ - xor{b}\t{%2, %0|%0, %2} - xor{b}\t{%2, %0|%0, %2} - xor{l}\t{%k2, %k0|%k0, %k2}" - [(set_attr "type" "alu") - (set_attr "mode" "QI,QI,SI")]) + "TARGET_SSE2" + "#") -(define_insn "*xorqi_1_slp" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) - (xor:QI (match_dup 0) - (match_operand:QI 1 "general_operand" "qn,qmn"))) - (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "xor{b}\t{%1, %0|%0, %1}" - [(set_attr "type" "alu1") - (set_attr "mode" "QI")]) +;; Splitters for fp abs and neg. -(define_insn "*xorqi_ext_0" - [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") - (const_int 8) - (const_int 8)) - (xor:SI - (zero_extract:SI - (match_operand 1 "ext_register_operand" "0") - (const_int 8) - (const_int 8)) - (match_operand 2 "const_int_operand" "n"))) +(define_split + [(set (match_operand 0 "fp_register_operand" "") + (match_operator 1 "absneg_operator" [(match_dup 0)])) + (use (match_operand 2 "" "")) (clobber (reg:CC FLAGS_REG))] - "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))" - "xor{b}\t{%2, %h0|%h0, %2}" - [(set_attr "type" "alu") - (set_attr "length_immediate" "1") - (set_attr "modrm" "1") - (set_attr "mode" "QI")]) + "reload_completed" + [(set (match_dup 0) (match_op_dup 1 [(match_dup 0)]))]) -(define_insn "*xorqi_ext_1" - [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") - (const_int 8) - (const_int 8)) - (xor:SI - (zero_extract:SI - (match_operand 1 "ext_register_operand" "0") - (const_int 8) - (const_int 8)) - (zero_extend:SI - (match_operand:QI 2 "general_operand" "Qm")))) +(define_split + [(set (match_operand 0 "register_operand" "") + (match_operator 3 "absneg_operator" + [(match_operand 1 "register_operand" "")])) + (use (match_operand 2 "nonimmediate_operand" "")) (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT - && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))" - "xor{b}\t{%2, %h0|%h0, %2}" - [(set_attr "type" "alu") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) + "reload_completed && SSE_REG_P (operands[0])" + [(set (match_dup 0) (match_dup 3))] +{ + enum machine_mode mode = GET_MODE (operands[0]); + enum machine_mode vmode = GET_MODE (operands[2]); + rtx tmp; -(define_insn "*xorqi_ext_1_rex64" - [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") - (const_int 8) - (const_int 8)) - (xor:SI - (zero_extract:SI - (match_operand 1 "ext_register_operand" "0") - (const_int 8) - (const_int 8)) - (zero_extend:SI - (match_operand 2 "ext_register_operand" "Q")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))" - "xor{b}\t{%2, %h0|%h0, %2}" - [(set_attr "type" "alu") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) + operands[0] = simplify_gen_subreg (vmode, operands[0], mode, 0); + operands[1] = simplify_gen_subreg (vmode, operands[1], mode, 0); + if (operands_match_p (operands[0], operands[2])) + { + tmp = operands[1]; + operands[1] = operands[2]; + operands[2] = tmp; + } + if (GET_CODE (operands[3]) == ABS) + tmp = gen_rtx_AND (vmode, operands[1], operands[2]); + else + tmp = gen_rtx_XOR (vmode, operands[1], operands[2]); + operands[3] = tmp; +}) -(define_insn "*xorqi_ext_2" - [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") - (const_int 8) - (const_int 8)) - (xor:SI - (zero_extract:SI (match_operand 1 "ext_register_operand" "0") - (const_int 8) - (const_int 8)) - (zero_extract:SI (match_operand 2 "ext_register_operand" "Q") - (const_int 8) - (const_int 8)))) +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (match_operator:SF 1 "absneg_operator" [(match_dup 0)])) + (use (match_operand:V4SF 2 "" "")) (clobber (reg:CC FLAGS_REG))] - "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))" - "xor{b}\t{%h2, %h0|%h0, %h2}" - [(set_attr "type" "alu") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) - -(define_insn "*xorqi_cc_1" - [(set (reg FLAGS_REG) - (compare - (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") - (match_operand:QI 2 "general_operand" "qmn,qn")) - (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm") - (xor:QI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCNOmode) - && ix86_binary_operator_ok (XOR, QImode, operands)" - "xor{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "QI")]) - -(define_insn "*xorqi_2_slp" - [(set (reg FLAGS_REG) - (compare (xor:QI (match_operand:QI 0 "nonimmediate_operand" "+q,qm") - (match_operand:QI 1 "general_operand" "qmn,qn")) - (const_int 0))) - (set (strict_low_part (match_dup 0)) - (xor:QI (match_dup 0) (match_dup 1)))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCNOmode) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "xor{b}\t{%1, %0|%0, %1}" - [(set_attr "type" "alu1") - (set_attr "mode" "QI")]) - -(define_insn "*xorqi_cc_2" - [(set (reg FLAGS_REG) - (compare - (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0") - (match_operand:QI 2 "general_operand" "qmn")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "ix86_match_ccmode (insn, CCNOmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "xor{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "QI")]) - -(define_insn "*xorqi_cc_ext_1" - [(set (reg FLAGS_REG) - (compare - (xor:SI - (zero_extract:SI - (match_operand 1 "ext_register_operand" "0") - (const_int 8) - (const_int 8)) - (match_operand:QI 2 "general_operand" "qmn")) - (const_int 0))) - (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q") - (const_int 8) - (const_int 8)) - (xor:SI - (zero_extract:SI (match_dup 1) (const_int 8) (const_int 8)) - (match_dup 2)))] - "!TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" - "xor{b}\t{%2, %h0|%h0, %2}" - [(set_attr "type" "alu") - (set_attr "modrm" "1") - (set_attr "mode" "QI")]) - -(define_insn "*xorqi_cc_ext_1_rex64" - [(set (reg FLAGS_REG) - (compare - (xor:SI - (zero_extract:SI - (match_operand 1 "ext_register_operand" "0") - (const_int 8) - (const_int 8)) - (match_operand:QI 2 "nonmemory_operand" "Qn")) - (const_int 0))) - (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") - (const_int 8) - (const_int 8)) - (xor:SI - (zero_extract:SI (match_dup 1) (const_int 8) (const_int 8)) - (match_dup 2)))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" - "xor{b}\t{%2, %h0|%h0, %2}" - [(set_attr "type" "alu") - (set_attr "modrm" "1") - (set_attr "mode" "QI")]) - -(define_expand "xorqi_cc_ext_1" - [(parallel [ - (set (reg:CCNO FLAGS_REG) - (compare:CCNO - (xor:SI - (zero_extract:SI - (match_operand 1 "ext_register_operand" "") - (const_int 8) - (const_int 8)) - (match_operand:QI 2 "general_operand" "")) - (const_int 0))) - (set (zero_extract:SI (match_operand 0 "ext_register_operand" "") - (const_int 8) - (const_int 8)) - (xor:SI - (zero_extract:SI (match_dup 1) (const_int 8) (const_int 8)) - (match_dup 2)))])] - "" - "") + "reload_completed" + [(parallel [(set (match_dup 0) (match_dup 1)) + (clobber (reg:CC FLAGS_REG))])] +{ + rtx tmp; + operands[0] = gen_lowpart (SImode, operands[0]); + if (GET_CODE (operands[1]) == ABS) + { + tmp = gen_int_mode (0x7fffffff, SImode); + tmp = gen_rtx_AND (SImode, operands[0], tmp); + } + else + { + tmp = gen_int_mode (0x80000000, SImode); + tmp = gen_rtx_XOR (SImode, operands[0], tmp); + } + operands[1] = tmp; +}) (define_split - [(set (match_operand 0 "register_operand" "") - (xor (match_operand 1 "register_operand" "") - (match_operand 2 "const_int_operand" ""))) + [(set (match_operand:DF 0 "register_operand" "") + (match_operator:DF 1 "absneg_operator" [(match_dup 0)])) + (use (match_operand 2 "" "")) (clobber (reg:CC FLAGS_REG))] - "reload_completed - && QI_REG_P (operands[0]) - && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && !(INTVAL (operands[2]) & ~(255 << 8)) - && GET_MODE (operands[0]) != QImode" - [(parallel [(set (zero_extract:SI (match_dup 0) (const_int 8) (const_int 8)) - (xor:SI (zero_extract:SI (match_dup 1) - (const_int 8) (const_int 8)) - (match_dup 2))) + "reload_completed" + [(parallel [(set (match_dup 0) (match_dup 1)) (clobber (reg:CC FLAGS_REG))])] - "operands[0] = gen_lowpart (SImode, operands[0]); - operands[1] = gen_lowpart (SImode, operands[1]); - operands[2] = gen_int_mode ((INTVAL (operands[2]) >> 8) & 0xff, SImode);") +{ + rtx tmp; + if (TARGET_64BIT) + { + tmp = gen_lowpart (DImode, operands[0]); + tmp = gen_rtx_ZERO_EXTRACT (DImode, tmp, const1_rtx, GEN_INT (63)); + operands[0] = tmp; + + if (GET_CODE (operands[1]) == ABS) + tmp = const0_rtx; + else + tmp = gen_rtx_NOT (DImode, tmp); + } + else + { + operands[0] = gen_highpart (SImode, operands[0]); + if (GET_CODE (operands[1]) == ABS) + { + tmp = gen_int_mode (0x7fffffff, SImode); + tmp = gen_rtx_AND (SImode, operands[0], tmp); + } + else + { + tmp = gen_int_mode (0x80000000, SImode); + tmp = gen_rtx_XOR (SImode, operands[0], tmp); + } + } + operands[1] = tmp; +}) -;; Since XOR can be encoded with sign extended immediate, this is only -;; profitable when 7th bit is set. (define_split - [(set (match_operand 0 "register_operand" "") - (xor (match_operand 1 "general_operand" "") - (match_operand 2 "const_int_operand" ""))) + [(set (match_operand:XF 0 "register_operand" "") + (match_operator:XF 1 "absneg_operator" [(match_dup 0)])) + (use (match_operand 2 "" "")) (clobber (reg:CC FLAGS_REG))] - "reload_completed - && ANY_QI_REG_P (operands[0]) - && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && !(INTVAL (operands[2]) & ~255) - && (INTVAL (operands[2]) & 128) - && GET_MODE (operands[0]) != QImode" - [(parallel [(set (strict_low_part (match_dup 0)) - (xor:QI (match_dup 1) - (match_dup 2))) + "reload_completed" + [(parallel [(set (match_dup 0) (match_dup 1)) (clobber (reg:CC FLAGS_REG))])] - "operands[0] = gen_lowpart (QImode, operands[0]); - operands[1] = gen_lowpart (QImode, operands[1]); - operands[2] = gen_lowpart (QImode, operands[2]);") - -;; Negation instructions +{ + rtx tmp; + operands[0] = gen_rtx_REG (SImode, + true_regnum (operands[0]) + + (TARGET_64BIT ? 1 : 2)); + if (GET_CODE (operands[1]) == ABS) + { + tmp = GEN_INT (0x7fff); + tmp = gen_rtx_AND (SImode, operands[0], tmp); + } + else + { + tmp = GEN_INT (0x8000); + tmp = gen_rtx_XOR (SImode, operands[0], tmp); + } + operands[1] = tmp; +}) -(define_expand "negti2" - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (neg:TI (match_operand:TI 1 "nonimmediate_operand" "")))] - "TARGET_64BIT" - "ix86_expand_unary_operator (NEG, TImode, operands); DONE;") +;; Conditionalize these after reload. If they match before reload, we +;; lose the clobber and ability to use integer instructions. -(define_insn "*negti2_1" - [(set (match_operand:TI 0 "nonimmediate_operand" "=ro") - (neg:TI (match_operand:TI 1 "nonimmediate_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && ix86_unary_operator_ok (NEG, TImode, operands)" - "#") +(define_insn "*2_1" + [(set (match_operand:X87MODEF 0 "register_operand" "=f") + (absneg:X87MODEF (match_operand:X87MODEF 1 "register_operand" "0")))] + "TARGET_80387 + && (reload_completed + || !(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH))" + "f" + [(set_attr "type" "fsgn") + (set_attr "mode" "")]) -(define_split - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (neg:TI (match_operand:TI 1 "nonimmediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(parallel - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (neg:DI (match_dup 1)) (const_int 0))) - (set (match_dup 0) (neg:DI (match_dup 1)))]) - (parallel - [(set (match_dup 2) - (plus:DI (plus:DI (ltu:DI (reg:CC FLAGS_REG) (const_int 0)) - (match_dup 3)) - (const_int 0))) - (clobber (reg:CC FLAGS_REG))]) - (parallel - [(set (match_dup 2) - (neg:DI (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] - "split_ti (&operands[0], 2, &operands[0], &operands[2]);") +(define_insn "*extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (absneg:DF (float_extend:DF + (match_operand:SF 1 "register_operand" "0"))))] + "TARGET_80387 && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387)" + "f" + [(set_attr "type" "fsgn") + (set_attr "mode" "DF")]) -(define_expand "negdi2" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (neg:DI (match_operand:DI 1 "nonimmediate_operand" "")))] - "" - "ix86_expand_unary_operator (NEG, DImode, operands); DONE;") +(define_insn "*extendsfxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (absneg:XF (float_extend:XF + (match_operand:SF 1 "register_operand" "0"))))] + "TARGET_80387" + "f" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF")]) -(define_insn "*negdi2_1" - [(set (match_operand:DI 0 "nonimmediate_operand" "=ro") - (neg:DI (match_operand:DI 1 "general_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT - && ix86_unary_operator_ok (NEG, DImode, operands)" - "#") +(define_insn "*extenddfxf2" + [(set (match_operand:XF 0 "register_operand" "=f") + (absneg:XF (float_extend:XF + (match_operand:DF 1 "register_operand" "0"))))] + "TARGET_80387" + "f" + [(set_attr "type" "fsgn") + (set_attr "mode" "XF")]) -(define_split - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (neg:DI (match_operand:DI 1 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && reload_completed" - [(parallel - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (neg:SI (match_dup 1)) (const_int 0))) - (set (match_dup 0) (neg:SI (match_dup 1)))]) - (parallel - [(set (match_dup 2) - (plus:SI (plus:SI (ltu:SI (reg:CC FLAGS_REG) (const_int 0)) - (match_dup 3)) - (const_int 0))) - (clobber (reg:CC FLAGS_REG))]) - (parallel - [(set (match_dup 2) - (neg:SI (match_dup 2))) - (clobber (reg:CC FLAGS_REG))])] - "split_di (&operands[0], 2, &operands[0], &operands[2]);"); +;; Copysign instructions -(define_insn "*negdi2_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (neg:DI (match_operand:DI 1 "nonimmediate_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_unary_operator_ok (NEG, DImode, operands)" - "neg{q}\t%0" - [(set_attr "type" "negnot") - (set_attr "mode" "DI")]) +(define_mode_iterator CSGNMODE [SF DF TF]) +(define_mode_attr CSGNVMODE [(SF "V4SF") (DF "V2DF") (TF "TF")]) -;; The problem with neg is that it does not perform (compare x 0), -;; it really performs (compare 0 x), which leaves us with the zero -;; flag being the only useful item. +(define_expand "copysign3" + [(match_operand:CSGNMODE 0 "register_operand" "") + (match_operand:CSGNMODE 1 "nonmemory_operand" "") + (match_operand:CSGNMODE 2 "register_operand" "")] + "(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) + || (TARGET_SSE2 && (mode == TFmode))" +{ + ix86_expand_copysign (operands); + DONE; +}) -(define_insn "*negdi2_cmpz_rex64" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (neg:DI (match_operand:DI 1 "nonimmediate_operand" "0")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (neg:DI (match_dup 1)))] - "TARGET_64BIT && ix86_unary_operator_ok (NEG, DImode, operands)" - "neg{q}\t%0" - [(set_attr "type" "negnot") - (set_attr "mode" "DI")]) +(define_insn_and_split "copysign3_const" + [(set (match_operand:CSGNMODE 0 "register_operand" "=x") + (unspec:CSGNMODE + [(match_operand: 1 "vector_move_operand" "xmC") + (match_operand:CSGNMODE 2 "register_operand" "0") + (match_operand: 3 "nonimmediate_operand" "xm")] + UNSPEC_COPYSIGN))] + "(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) + || (TARGET_SSE2 && (mode == TFmode))" + "#" + "&& reload_completed" + [(const_int 0)] +{ + ix86_split_copysign_const (operands); + DONE; +}) +(define_insn "copysign3_var" + [(set (match_operand:CSGNMODE 0 "register_operand" "=x,x,x,x,x") + (unspec:CSGNMODE + [(match_operand:CSGNMODE 2 "register_operand" "x,0,0,x,x") + (match_operand:CSGNMODE 3 "register_operand" "1,1,x,1,x") + (match_operand: 4 "nonimmediate_operand" "X,xm,xm,0,0") + (match_operand: 5 "nonimmediate_operand" "0,xm,1,xm,1")] + UNSPEC_COPYSIGN)) + (clobber (match_scratch: 1 "=x,x,x,x,x"))] + "(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) + || (TARGET_SSE2 && (mode == TFmode))" + "#") -(define_expand "negsi2" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (neg:SI (match_operand:SI 1 "nonimmediate_operand" "")))] +(define_split + [(set (match_operand:CSGNMODE 0 "register_operand" "") + (unspec:CSGNMODE + [(match_operand:CSGNMODE 2 "register_operand" "") + (match_operand:CSGNMODE 3 "register_operand" "") + (match_operand: 4 "" "") + (match_operand: 5 "" "")] + UNSPEC_COPYSIGN)) + (clobber (match_scratch: 1 ""))] + "((SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) + || (TARGET_SSE2 && (mode == TFmode))) + && reload_completed" + [(const_int 0)] +{ + ix86_split_copysign_var (operands); + DONE; +}) + +;; One complement instructions + +(define_expand "one_cmpl2" + [(set (match_operand:SWIM 0 "nonimmediate_operand" "") + (not:SWIM (match_operand:SWIM 1 "nonimmediate_operand" "")))] "" - "ix86_expand_unary_operator (NEG, SImode, operands); DONE;") + "ix86_expand_unary_operator (NOT, mode, operands); DONE;") -(define_insn "*negsi2_1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_unary_operator_ok (NEG, SImode, operands)" - "neg{l}\t%0" +(define_insn "*one_cmpl2_1" + [(set (match_operand:SWI248 0 "nonimmediate_operand" "=rm") + (not:SWI248 (match_operand:SWI248 1 "nonimmediate_operand" "0")))] + "ix86_unary_operator_ok (NOT, mode, operands)" + "not{}\t%0" [(set_attr "type" "negnot") - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) -;; Combine is quite creative about this pattern. -(define_insn "*negsi2_1_zext" +;; %%% Potential partial reg stall on alternative 1. What to do? +(define_insn "*one_cmplqi2_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r") + (not:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")))] + "ix86_unary_operator_ok (NOT, QImode, operands)" + "@ + not{b}\t%0 + not{l}\t%k0" + [(set_attr "type" "negnot") + (set_attr "mode" "QI,SI")]) + +;; ??? Currently never generated - xor is used instead. +(define_insn "*one_cmplsi2_1_zext" [(set (match_operand:DI 0 "register_operand" "=r") - (lshiftrt:DI (neg:DI (ashift:DI (match_operand:DI 1 "register_operand" "0") - (const_int 32))) - (const_int 32))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_unary_operator_ok (NEG, SImode, operands)" - "neg{l}\t%k0" + (zero_extend:DI + (not:SI (match_operand:SI 1 "register_operand" "0"))))] + "TARGET_64BIT && ix86_unary_operator_ok (NOT, SImode, operands)" + "not{l}\t%k0" [(set_attr "type" "negnot") (set_attr "mode" "SI")]) -;; The problem with neg is that it does not perform (compare x 0), -;; it really performs (compare 0 x), which leaves us with the zero -;; flag being the only useful item. +(define_insn "*one_cmpl2_2" + [(set (reg FLAGS_REG) + (compare (not:SWI (match_operand:SWI 1 "nonimmediate_operand" "0")) + (const_int 0))) + (set (match_operand:SWI 0 "nonimmediate_operand" "=m") + (not:SWI (match_dup 1)))] + "ix86_match_ccmode (insn, CCNOmode) + && ix86_unary_operator_ok (NOT, mode, operands)" + "#" + [(set_attr "type" "alu1") + (set_attr "mode" "")]) -(define_insn "*negsi2_cmpz" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")) - (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (neg:SI (match_dup 1)))] - "ix86_unary_operator_ok (NEG, SImode, operands)" - "neg{l}\t%0" - [(set_attr "type" "negnot") - (set_attr "mode" "SI")]) +(define_split + [(set (match_operand 0 "flags_reg_operand" "") + (match_operator 2 "compare_operator" + [(not:SWI (match_operand:SWI 3 "nonimmediate_operand" "")) + (const_int 0)])) + (set (match_operand:SWI 1 "nonimmediate_operand" "") + (not:SWI (match_dup 3)))] + "ix86_match_ccmode (insn, CCNOmode)" + [(parallel [(set (match_dup 0) + (match_op_dup 2 [(xor:SWI (match_dup 3) (const_int -1)) + (const_int 0)])) + (set (match_dup 1) + (xor:SWI (match_dup 3) (const_int -1)))])] + "") -(define_insn "*negsi2_cmpz_zext" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (lshiftrt:DI - (neg:DI (ashift:DI - (match_operand:DI 1 "register_operand" "0") - (const_int 32))) - (const_int 32)) - (const_int 0))) +;; ??? Currently never generated - xor is used instead. +(define_insn "*one_cmplsi2_2_zext" + [(set (reg FLAGS_REG) + (compare (not:SI (match_operand:SI 1 "register_operand" "0")) + (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") - (lshiftrt:DI (neg:DI (ashift:DI (match_dup 1) - (const_int 32))) - (const_int 32)))] - "TARGET_64BIT && ix86_unary_operator_ok (NEG, SImode, operands)" - "neg{l}\t%k0" - [(set_attr "type" "negnot") + (zero_extend:DI (not:SI (match_dup 1))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) + && ix86_unary_operator_ok (NOT, SImode, operands)" + "#" + [(set_attr "type" "alu1") (set_attr "mode" "SI")]) -(define_expand "neghi2" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (neg:HI (match_operand:HI 1 "nonimmediate_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_unary_operator (NEG, HImode, operands); DONE;") - -(define_insn "*neghi2_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_unary_operator_ok (NEG, HImode, operands)" - "neg{w}\t%0" - [(set_attr "type" "negnot") - (set_attr "mode" "HI")]) +(define_split + [(set (match_operand 0 "flags_reg_operand" "") + (match_operator 2 "compare_operator" + [(not:SI (match_operand:SI 3 "register_operand" "")) + (const_int 0)])) + (set (match_operand:DI 1 "register_operand" "") + (zero_extend:DI (not:SI (match_dup 3))))] + "ix86_match_ccmode (insn, CCNOmode)" + [(parallel [(set (match_dup 0) + (match_op_dup 2 [(xor:SI (match_dup 3) (const_int -1)) + (const_int 0)])) + (set (match_dup 1) + (zero_extend:DI (xor:SI (match_dup 3) (const_int -1))))])] + "") + +;; Shift instructions -(define_insn "*neghi2_cmpz" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (neg:HI (match_dup 1)))] - "ix86_unary_operator_ok (NEG, HImode, operands)" - "neg{w}\t%0" - [(set_attr "type" "negnot") - (set_attr "mode" "HI")]) +;; DImode shifts are implemented using the i386 "shift double" opcode, +;; which is written as "sh[lr]d[lw] imm,reg,reg/mem". If the shift count +;; is variable, then the count is in %cl and the "imm" operand is dropped +;; from the assembler input. +;; +;; This instruction shifts the target reg/mem as usual, but instead of +;; shifting in zeros, bits are shifted in from reg operand. If the insn +;; is a left shift double, bits are taken from the high order bits of +;; reg, else if the insn is a shift right double, bits are taken from the +;; low order bits of reg. So if %eax is "1234" and %edx is "5678", +;; "shldl $8,%edx,%eax" leaves %edx unchanged and sets %eax to "2345". +;; +;; Since sh[lr]d does not change the `reg' operand, that is done +;; separately, making all shifts emit pairs of shift double and normal +;; shift. Since sh[lr]d does not shift more than 31 bits, and we wish to +;; support a 63 bit shift, each shift where the count is in a reg expands +;; to a pair of shifts, a branch, a shift by 32 and a label. +;; +;; If the shift count is a constant, we need never emit more than one +;; shift pair, instead using moves and sign extension for counts greater +;; than 31. -(define_expand "negqi2" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (neg:QI (match_operand:QI 1 "nonimmediate_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_unary_operator (NEG, QImode, operands); DONE;") +(define_expand "ashl3" + [(set (match_operand:SDWIM 0 "" "") + (ashift:SDWIM (match_operand:SDWIM 1 "" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "ix86_expand_binary_operator (ASHIFT, mode, operands); DONE;") -(define_insn "*negqi2_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0"))) +(define_insn "*ashl3_doubleword" + [(set (match_operand:DWI 0 "register_operand" "=&r,r") + (ashift:DWI (match_operand:DWI 1 "reg_or_pm1_operand" "n,0") + (match_operand:QI 2 "nonmemory_operand" "c,c"))) (clobber (reg:CC FLAGS_REG))] - "ix86_unary_operator_ok (NEG, QImode, operands)" - "neg{b}\t%0" - [(set_attr "type" "negnot") - (set_attr "mode" "QI")]) + "" + "#" + [(set_attr "type" "multi")]) -(define_insn "*negqi2_cmpz" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")) - (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (neg:QI (match_dup 1)))] - "ix86_unary_operator_ok (NEG, QImode, operands)" - "neg{b}\t%0" - [(set_attr "type" "negnot") - (set_attr "mode" "QI")]) +(define_split + [(set (match_operand:DWI 0 "register_operand" "") + (ashift:DWI (match_operand:DWI 1 "nonmemory_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC FLAGS_REG))] + "(optimize && flag_peephole2) ? epilogue_completed : reload_completed" + [(const_int 0)] + "ix86_split_ashl (operands, NULL_RTX, mode); DONE;") -;; Changing of sign for FP values is doable using integer unit too. +;; By default we don't ask for a scratch register, because when DWImode +;; values are manipulated, registers are already at a premium. But if +;; we have one handy, we won't turn it away. -(define_expand "2" - [(set (match_operand:X87MODEF 0 "register_operand" "") - (absneg:X87MODEF (match_operand:X87MODEF 1 "register_operand" "")))] - "TARGET_80387 || (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)" - "ix86_expand_fp_absneg_operator (, mode, operands); DONE;") +(define_peephole2 + [(match_scratch:DWIH 3 "r") + (parallel [(set (match_operand: 0 "register_operand" "") + (ashift: + (match_operand: 1 "nonmemory_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC FLAGS_REG))]) + (match_dup 3)] + "TARGET_CMOVE" + [(const_int 0)] + "ix86_split_ashl (operands, operands[3], mode); DONE;") -(define_insn "*absneg2_mixed" - [(set (match_operand:MODEF 0 "register_operand" "=x,x,f,!r") - (match_operator:MODEF 3 "absneg_operator" - [(match_operand:MODEF 1 "register_operand" "0,x,0,0")])) - (use (match_operand: 2 "nonimmediate_operand" "xm,0,X,X")) +(define_insn "x86_64_shld" + [(set (match_operand:DI 0 "nonimmediate_operand" "+r*m") + (ior:DI (ashift:DI (match_dup 0) + (match_operand:QI 2 "nonmemory_operand" "Jc")) + (lshiftrt:DI (match_operand:DI 1 "register_operand" "r") + (minus:QI (const_int 64) (match_dup 2))))) (clobber (reg:CC FLAGS_REG))] - "TARGET_MIX_SSE_I387 && SSE_FLOAT_MODE_P (mode)" - "#") + "TARGET_64BIT" + "shld{q}\t{%s2%1, %0|%0, %1, %2}" + [(set_attr "type" "ishift") + (set_attr "prefix_0f" "1") + (set_attr "mode" "DI") + (set_attr "athlon_decode" "vector") + (set_attr "amdfam10_decode" "vector")]) -(define_insn "*absneg2_sse" - [(set (match_operand:MODEF 0 "register_operand" "=x,x,!r") - (match_operator:MODEF 3 "absneg_operator" - [(match_operand:MODEF 1 "register_operand" "0 ,x,0")])) - (use (match_operand: 2 "register_operand" "xm,0,X")) +(define_insn "x86_shld" + [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m") + (ior:SI (ashift:SI (match_dup 0) + (match_operand:QI 2 "nonmemory_operand" "Ic")) + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + (minus:QI (const_int 32) (match_dup 2))))) (clobber (reg:CC FLAGS_REG))] - "SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH" - "#") + "" + "shld{l}\t{%s2%1, %0|%0, %1, %2}" + [(set_attr "type" "ishift") + (set_attr "prefix_0f" "1") + (set_attr "mode" "SI") + (set_attr "pent_pair" "np") + (set_attr "athlon_decode" "vector") + (set_attr "amdfam10_decode" "vector")]) -(define_insn "*absneg2_i387" - [(set (match_operand:X87MODEF 0 "register_operand" "=f,!r") - (match_operator:X87MODEF 3 "absneg_operator" - [(match_operand:X87MODEF 1 "register_operand" "0,0")])) - (use (match_operand 2 "" "")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_80387 && !(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)" - "#") +(define_expand "x86_shift_adj_1" + [(set (reg:CCZ FLAGS_REG) + (compare:CCZ (and:QI (match_operand:QI 2 "register_operand" "") + (match_dup 4)) + (const_int 0))) + (set (match_operand:SWI48 0 "register_operand" "") + (if_then_else:SWI48 (ne (reg:CCZ FLAGS_REG) (const_int 0)) + (match_operand:SWI48 1 "register_operand" "") + (match_dup 0))) + (set (match_dup 1) + (if_then_else:SWI48 (ne (reg:CCZ FLAGS_REG) (const_int 0)) + (match_operand:SWI48 3 "register_operand" "r") + (match_dup 1)))] + "TARGET_CMOVE" + "operands[4] = GEN_INT (GET_MODE_BITSIZE (mode));") -(define_expand "tf2" - [(set (match_operand:TF 0 "register_operand" "") - (absneg:TF (match_operand:TF 1 "register_operand" "")))] - "TARGET_SSE2" - "ix86_expand_fp_absneg_operator (, TFmode, operands); DONE;") +(define_expand "x86_shift_adj_2" + [(use (match_operand:SWI48 0 "register_operand" "")) + (use (match_operand:SWI48 1 "register_operand" "")) + (use (match_operand:QI 2 "register_operand" ""))] + "" +{ + rtx label = gen_label_rtx (); + rtx tmp; -(define_insn "*absnegtf2_sse" - [(set (match_operand:TF 0 "register_operand" "=x,x") - (match_operator:TF 3 "absneg_operator" - [(match_operand:TF 1 "register_operand" "0,x")])) - (use (match_operand:TF 2 "nonimmediate_operand" "xm,0")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_SSE2" - "#") + emit_insn (gen_testqi_ccz_1 (operands[2], + GEN_INT (GET_MODE_BITSIZE (mode)))); -;; Splitters for fp abs and neg. + tmp = gen_rtx_REG (CCZmode, FLAGS_REG); + tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); + tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, + gen_rtx_LABEL_REF (VOIDmode, label), + pc_rtx); + tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); + JUMP_LABEL (tmp) = label; -(define_split - [(set (match_operand 0 "fp_register_operand" "") - (match_operator 1 "absneg_operator" [(match_dup 0)])) - (use (match_operand 2 "" "")) - (clobber (reg:CC FLAGS_REG))] - "reload_completed" - [(set (match_dup 0) (match_op_dup 1 [(match_dup 0)]))]) + emit_move_insn (operands[0], operands[1]); + ix86_expand_clear (operands[1]); -(define_split - [(set (match_operand 0 "register_operand" "") - (match_operator 3 "absneg_operator" - [(match_operand 1 "register_operand" "")])) - (use (match_operand 2 "nonimmediate_operand" "")) - (clobber (reg:CC FLAGS_REG))] - "reload_completed && SSE_REG_P (operands[0])" - [(set (match_dup 0) (match_dup 3))] -{ - enum machine_mode mode = GET_MODE (operands[0]); - enum machine_mode vmode = GET_MODE (operands[2]); - rtx tmp; + emit_label (label); + LABEL_NUSES (label) = 1; - operands[0] = simplify_gen_subreg (vmode, operands[0], mode, 0); - operands[1] = simplify_gen_subreg (vmode, operands[1], mode, 0); - if (operands_match_p (operands[0], operands[2])) - { - tmp = operands[1]; - operands[1] = operands[2]; - operands[2] = tmp; - } - if (GET_CODE (operands[3]) == ABS) - tmp = gen_rtx_AND (vmode, operands[1], operands[2]); - else - tmp = gen_rtx_XOR (vmode, operands[1], operands[2]); - operands[3] = tmp; + DONE; }) -(define_split - [(set (match_operand:SF 0 "register_operand" "") - (match_operator:SF 1 "absneg_operator" [(match_dup 0)])) - (use (match_operand:V4SF 2 "" "")) +(define_insn "*ashl3_1" + [(set (match_operand:SWI48 0 "nonimmediate_operand" "=rm,r") + (ashift:SWI48 (match_operand:SWI48 1 "nonimmediate_operand" "0,l") + (match_operand:QI 2 "nonmemory_operand" "c,M"))) (clobber (reg:CC FLAGS_REG))] - "reload_completed" - [(parallel [(set (match_dup 0) (match_dup 1)) - (clobber (reg:CC FLAGS_REG))])] + "ix86_binary_operator_ok (ASHIFT, mode, operands)" { - rtx tmp; - operands[0] = gen_lowpart (SImode, operands[0]); - if (GET_CODE (operands[1]) == ABS) - { - tmp = gen_int_mode (0x7fffffff, SImode); - tmp = gen_rtx_AND (SImode, operands[0], tmp); - } - else + switch (get_attr_type (insn)) { - tmp = gen_int_mode (0x80000000, SImode); - tmp = gen_rtx_XOR (SImode, operands[0], tmp); + case TYPE_LEA: + return "#"; + + case TYPE_ALU: + gcc_assert (operands[2] == const1_rtx); + gcc_assert (rtx_equal_p (operands[0], operands[1])); + return "add{}\t%0, %0"; + + default: + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "sal{}\t%0"; + else + return "sal{}\t{%2, %0|%0, %2}"; } - operands[1] = tmp; -}) +} + [(set (attr "type") + (cond [(eq_attr "alternative" "1") + (const_string "lea") + (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set (attr "length_immediate") + (if_then_else + (ior (eq_attr "type" "alu") + (and (eq_attr "type" "ishift") + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "")]) -(define_split - [(set (match_operand:DF 0 "register_operand" "") - (match_operator:DF 1 "absneg_operator" [(match_dup 0)])) - (use (match_operand 2 "" "")) +(define_insn "*ashlsi3_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI + (ashift:SI (match_operand:SI 1 "register_operand" "0,l") + (match_operand:QI 2 "nonmemory_operand" "cI,M")))) (clobber (reg:CC FLAGS_REG))] - "reload_completed" - [(parallel [(set (match_dup 0) (match_dup 1)) - (clobber (reg:CC FLAGS_REG))])] + "TARGET_64BIT && ix86_binary_operator_ok (ASHIFT, SImode, operands)" { - rtx tmp; - if (TARGET_64BIT) + switch (get_attr_type (insn)) { - tmp = gen_lowpart (DImode, operands[0]); - tmp = gen_rtx_ZERO_EXTRACT (DImode, tmp, const1_rtx, GEN_INT (63)); - operands[0] = tmp; + case TYPE_LEA: + return "#"; - if (GET_CODE (operands[1]) == ABS) - tmp = const0_rtx; + case TYPE_ALU: + gcc_assert (operands[2] == const1_rtx); + return "add{l}\t%k0, %k0"; + + default: + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "sal{l}\t%k0"; else - tmp = gen_rtx_NOT (DImode, tmp); + return "sal{l}\t{%2, %k0|%k0, %2}"; } - else +} + [(set (attr "type") + (cond [(eq_attr "alternative" "1") + (const_string "lea") + (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set (attr "length_immediate") + (if_then_else + (ior (eq_attr "type" "alu") + (and (eq_attr "type" "ishift") + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "SI")]) + +(define_insn "*ashlhi3_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "cI"))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (ASHIFT, HImode, operands)" +{ + switch (get_attr_type (insn)) { - operands[0] = gen_highpart (SImode, operands[0]); - if (GET_CODE (operands[1]) == ABS) - { - tmp = gen_int_mode (0x7fffffff, SImode); - tmp = gen_rtx_AND (SImode, operands[0], tmp); - } + case TYPE_ALU: + gcc_assert (operands[2] == const1_rtx); + return "add{w}\t%0, %0"; + + default: + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "sal{w}\t%0"; else - { - tmp = gen_int_mode (0x80000000, SImode); - tmp = gen_rtx_XOR (SImode, operands[0], tmp); - } + return "sal{w}\t{%2, %0|%0, %2}"; } - operands[1] = tmp; -}) +} + [(set (attr "type") + (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set (attr "length_immediate") + (if_then_else + (ior (eq_attr "type" "alu") + (and (eq_attr "type" "ishift") + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "HI")]) -(define_split - [(set (match_operand:XF 0 "register_operand" "") - (match_operator:XF 1 "absneg_operator" [(match_dup 0)])) - (use (match_operand 2 "" "")) +(define_insn "*ashlhi3_1_lea" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0,l") + (match_operand:QI 2 "nonmemory_operand" "cI,M"))) (clobber (reg:CC FLAGS_REG))] - "reload_completed" - [(parallel [(set (match_dup 0) (match_dup 1)) - (clobber (reg:CC FLAGS_REG))])] + "!TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (ASHIFT, HImode, operands)" { - rtx tmp; - operands[0] = gen_rtx_REG (SImode, - true_regnum (operands[0]) - + (TARGET_64BIT ? 1 : 2)); - if (GET_CODE (operands[1]) == ABS) - { - tmp = GEN_INT (0x7fff); - tmp = gen_rtx_AND (SImode, operands[0], tmp); - } - else + switch (get_attr_type (insn)) { - tmp = GEN_INT (0x8000); - tmp = gen_rtx_XOR (SImode, operands[0], tmp); - } - operands[1] = tmp; -}) - -;; Conditionalize these after reload. If they match before reload, we -;; lose the clobber and ability to use integer instructions. + case TYPE_LEA: + return "#"; -(define_insn "*2_1" - [(set (match_operand:X87MODEF 0 "register_operand" "=f") - (absneg:X87MODEF (match_operand:X87MODEF 1 "register_operand" "0")))] - "TARGET_80387 - && (reload_completed - || !(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH))" - "f" - [(set_attr "type" "fsgn") - (set_attr "mode" "")]) - -(define_insn "*extendsfdf2" - [(set (match_operand:DF 0 "register_operand" "=f") - (absneg:DF (float_extend:DF - (match_operand:SF 1 "register_operand" "0"))))] - "TARGET_80387 && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387)" - "f" - [(set_attr "type" "fsgn") - (set_attr "mode" "DF")]) - -(define_insn "*extendsfxf2" - [(set (match_operand:XF 0 "register_operand" "=f") - (absneg:XF (float_extend:XF - (match_operand:SF 1 "register_operand" "0"))))] - "TARGET_80387" - "f" - [(set_attr "type" "fsgn") - (set_attr "mode" "XF")]) - -(define_insn "*extenddfxf2" - [(set (match_operand:XF 0 "register_operand" "=f") - (absneg:XF (float_extend:XF - (match_operand:DF 1 "register_operand" "0"))))] - "TARGET_80387" - "f" - [(set_attr "type" "fsgn") - (set_attr "mode" "XF")]) - -;; Copysign instructions - -(define_mode_iterator CSGNMODE [SF DF TF]) -(define_mode_attr CSGNVMODE [(SF "V4SF") (DF "V2DF") (TF "TF")]) - -(define_expand "copysign3" - [(match_operand:CSGNMODE 0 "register_operand" "") - (match_operand:CSGNMODE 1 "nonmemory_operand" "") - (match_operand:CSGNMODE 2 "register_operand" "")] - "(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) - || (TARGET_SSE2 && (mode == TFmode))" -{ - ix86_expand_copysign (operands); - DONE; -}) - -(define_insn_and_split "copysign3_const" - [(set (match_operand:CSGNMODE 0 "register_operand" "=x") - (unspec:CSGNMODE - [(match_operand: 1 "vector_move_operand" "xmC") - (match_operand:CSGNMODE 2 "register_operand" "0") - (match_operand: 3 "nonimmediate_operand" "xm")] - UNSPEC_COPYSIGN))] - "(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) - || (TARGET_SSE2 && (mode == TFmode))" - "#" - "&& reload_completed" - [(const_int 0)] -{ - ix86_split_copysign_const (operands); - DONE; -}) - -(define_insn "copysign3_var" - [(set (match_operand:CSGNMODE 0 "register_operand" "=x,x,x,x,x") - (unspec:CSGNMODE - [(match_operand:CSGNMODE 2 "register_operand" "x,0,0,x,x") - (match_operand:CSGNMODE 3 "register_operand" "1,1,x,1,x") - (match_operand: 4 "nonimmediate_operand" "X,xm,xm,0,0") - (match_operand: 5 "nonimmediate_operand" "0,xm,1,xm,1")] - UNSPEC_COPYSIGN)) - (clobber (match_scratch: 1 "=x,x,x,x,x"))] - "(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) - || (TARGET_SSE2 && (mode == TFmode))" - "#") - -(define_split - [(set (match_operand:CSGNMODE 0 "register_operand" "") - (unspec:CSGNMODE - [(match_operand:CSGNMODE 2 "register_operand" "") - (match_operand:CSGNMODE 3 "register_operand" "") - (match_operand: 4 "" "") - (match_operand: 5 "" "")] - UNSPEC_COPYSIGN)) - (clobber (match_scratch: 1 ""))] - "((SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) - || (TARGET_SSE2 && (mode == TFmode))) - && reload_completed" - [(const_int 0)] -{ - ix86_split_copysign_var (operands); - DONE; -}) - -;; One complement instructions - -(define_expand "one_cmpldi2" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (not:DI (match_operand:DI 1 "nonimmediate_operand" "")))] - "TARGET_64BIT" - "ix86_expand_unary_operator (NOT, DImode, operands); DONE;") - -(define_insn "*one_cmpldi2_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (not:DI (match_operand:DI 1 "nonimmediate_operand" "0")))] - "TARGET_64BIT && ix86_unary_operator_ok (NOT, DImode, operands)" - "not{q}\t%0" - [(set_attr "type" "negnot") - (set_attr "mode" "DI")]) - -(define_insn "*one_cmpldi2_2_rex64" - [(set (reg FLAGS_REG) - (compare (not:DI (match_operand:DI 1 "nonimmediate_operand" "0")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (not:DI (match_dup 1)))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) - && ix86_unary_operator_ok (NOT, DImode, operands)" - "#" - [(set_attr "type" "alu1") - (set_attr "mode" "DI")]) - -(define_split - [(set (match_operand 0 "flags_reg_operand" "") - (match_operator 2 "compare_operator" - [(not:DI (match_operand:DI 3 "nonimmediate_operand" "")) - (const_int 0)])) - (set (match_operand:DI 1 "nonimmediate_operand" "") - (not:DI (match_dup 3)))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" - [(parallel [(set (match_dup 0) - (match_op_dup 2 - [(xor:DI (match_dup 3) (const_int -1)) - (const_int 0)])) - (set (match_dup 1) - (xor:DI (match_dup 3) (const_int -1)))])] - "") - -(define_expand "one_cmplsi2" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (not:SI (match_operand:SI 1 "nonimmediate_operand" "")))] - "" - "ix86_expand_unary_operator (NOT, SImode, operands); DONE;") - -(define_insn "*one_cmplsi2_1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))] - "ix86_unary_operator_ok (NOT, SImode, operands)" - "not{l}\t%0" - [(set_attr "type" "negnot") - (set_attr "mode" "SI")]) - -;; ??? Currently never generated - xor is used instead. -(define_insn "*one_cmplsi2_1_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (not:SI (match_operand:SI 1 "register_operand" "0"))))] - "TARGET_64BIT && ix86_unary_operator_ok (NOT, SImode, operands)" - "not{l}\t%k0" - [(set_attr "type" "negnot") - (set_attr "mode" "SI")]) - -(define_insn "*one_cmplsi2_2" - [(set (reg FLAGS_REG) - (compare (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")) - (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (not:SI (match_dup 1)))] - "ix86_match_ccmode (insn, CCNOmode) - && ix86_unary_operator_ok (NOT, SImode, operands)" - "#" - [(set_attr "type" "alu1") - (set_attr "mode" "SI")]) - -(define_split - [(set (match_operand 0 "flags_reg_operand" "") - (match_operator 2 "compare_operator" - [(not:SI (match_operand:SI 3 "nonimmediate_operand" "")) - (const_int 0)])) - (set (match_operand:SI 1 "nonimmediate_operand" "") - (not:SI (match_dup 3)))] - "ix86_match_ccmode (insn, CCNOmode)" - [(parallel [(set (match_dup 0) - (match_op_dup 2 [(xor:SI (match_dup 3) (const_int -1)) - (const_int 0)])) - (set (match_dup 1) - (xor:SI (match_dup 3) (const_int -1)))])] - "") - -;; ??? Currently never generated - xor is used instead. -(define_insn "*one_cmplsi2_2_zext" - [(set (reg FLAGS_REG) - (compare (not:SI (match_operand:SI 1 "register_operand" "0")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (not:SI (match_dup 1))))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode) - && ix86_unary_operator_ok (NOT, SImode, operands)" - "#" - [(set_attr "type" "alu1") - (set_attr "mode" "SI")]) - -(define_split - [(set (match_operand 0 "flags_reg_operand" "") - (match_operator 2 "compare_operator" - [(not:SI (match_operand:SI 3 "register_operand" "")) - (const_int 0)])) - (set (match_operand:DI 1 "register_operand" "") - (zero_extend:DI (not:SI (match_dup 3))))] - "ix86_match_ccmode (insn, CCNOmode)" - [(parallel [(set (match_dup 0) - (match_op_dup 2 [(xor:SI (match_dup 3) (const_int -1)) - (const_int 0)])) - (set (match_dup 1) - (zero_extend:DI (xor:SI (match_dup 3) (const_int -1))))])] - "") - -(define_expand "one_cmplhi2" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (not:HI (match_operand:HI 1 "nonimmediate_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_unary_operator (NOT, HImode, operands); DONE;") - -(define_insn "*one_cmplhi2_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))] - "ix86_unary_operator_ok (NOT, HImode, operands)" - "not{w}\t%0" - [(set_attr "type" "negnot") - (set_attr "mode" "HI")]) - -(define_insn "*one_cmplhi2_2" - [(set (reg FLAGS_REG) - (compare (not:HI (match_operand:HI 1 "nonimmediate_operand" "0")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (not:HI (match_dup 1)))] - "ix86_match_ccmode (insn, CCNOmode) - && ix86_unary_operator_ok (NEG, HImode, operands)" - "#" - [(set_attr "type" "alu1") - (set_attr "mode" "HI")]) - -(define_split - [(set (match_operand 0 "flags_reg_operand" "") - (match_operator 2 "compare_operator" - [(not:HI (match_operand:HI 3 "nonimmediate_operand" "")) - (const_int 0)])) - (set (match_operand:HI 1 "nonimmediate_operand" "") - (not:HI (match_dup 3)))] - "ix86_match_ccmode (insn, CCNOmode)" - [(parallel [(set (match_dup 0) - (match_op_dup 2 [(xor:HI (match_dup 3) (const_int -1)) - (const_int 0)])) - (set (match_dup 1) - (xor:HI (match_dup 3) (const_int -1)))])] - "") - -;; %%% Potential partial reg stall on alternative 1. What to do? -(define_expand "one_cmplqi2" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (not:QI (match_operand:QI 1 "nonimmediate_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_unary_operator (NOT, QImode, operands); DONE;") - -(define_insn "*one_cmplqi2_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r") - (not:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")))] - "ix86_unary_operator_ok (NOT, QImode, operands)" - "@ - not{b}\t%0 - not{l}\t%k0" - [(set_attr "type" "negnot") - (set_attr "mode" "QI,SI")]) - -(define_insn "*one_cmplqi2_2" - [(set (reg FLAGS_REG) - (compare (not:QI (match_operand:QI 1 "nonimmediate_operand" "0")) - (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (not:QI (match_dup 1)))] - "ix86_match_ccmode (insn, CCNOmode) - && ix86_unary_operator_ok (NOT, QImode, operands)" - "#" - [(set_attr "type" "alu1") - (set_attr "mode" "QI")]) - -(define_split - [(set (match_operand 0 "flags_reg_operand" "") - (match_operator 2 "compare_operator" - [(not:QI (match_operand:QI 3 "nonimmediate_operand" "")) - (const_int 0)])) - (set (match_operand:QI 1 "nonimmediate_operand" "") - (not:QI (match_dup 3)))] - "ix86_match_ccmode (insn, CCNOmode)" - [(parallel [(set (match_dup 0) - (match_op_dup 2 [(xor:QI (match_dup 3) (const_int -1)) - (const_int 0)])) - (set (match_dup 1) - (xor:QI (match_dup 3) (const_int -1)))])] - "") - -;; Arithmetic shift instructions - -;; DImode shifts are implemented using the i386 "shift double" opcode, -;; which is written as "sh[lr]d[lw] imm,reg,reg/mem". If the shift count -;; is variable, then the count is in %cl and the "imm" operand is dropped -;; from the assembler input. -;; -;; This instruction shifts the target reg/mem as usual, but instead of -;; shifting in zeros, bits are shifted in from reg operand. If the insn -;; is a left shift double, bits are taken from the high order bits of -;; reg, else if the insn is a shift right double, bits are taken from the -;; low order bits of reg. So if %eax is "1234" and %edx is "5678", -;; "shldl $8,%edx,%eax" leaves %edx unchanged and sets %eax to "2345". -;; -;; Since sh[lr]d does not change the `reg' operand, that is done -;; separately, making all shifts emit pairs of shift double and normal -;; shift. Since sh[lr]d does not shift more than 31 bits, and we wish to -;; support a 63 bit shift, each shift where the count is in a reg expands -;; to a pair of shifts, a branch, a shift by 32 and a label. -;; -;; If the shift count is a constant, we need never emit more than one -;; shift pair, instead using moves and sign extension for counts greater -;; than 31. - -(define_expand "ashlti3" - [(set (match_operand:TI 0 "register_operand" "") - (ashift:TI (match_operand:TI 1 "reg_or_pm1_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_64BIT" - "ix86_expand_binary_operator (ASHIFT, TImode, operands); DONE;") - -;; This pattern must be defined before *ashlti3_1 to prevent -;; combine pass from converting sse2_ashlti3 to *ashlti3_1. - -(define_insn "*avx_ashlti3" - [(set (match_operand:TI 0 "register_operand" "=x") - (ashift:TI (match_operand:TI 1 "register_operand" "x") - (match_operand:SI 2 "const_0_to_255_mul_8_operand" "n")))] - "TARGET_AVX" -{ - operands[2] = GEN_INT (INTVAL (operands[2]) / 8); - return "vpslldq\t{%2, %1, %0|%0, %1, %2}"; -} - [(set_attr "type" "sseishft") - (set_attr "prefix" "vex") - (set_attr "length_immediate" "1") - (set_attr "mode" "TI")]) - -(define_insn "sse2_ashlti3" - [(set (match_operand:TI 0 "register_operand" "=x") - (ashift:TI (match_operand:TI 1 "register_operand" "0") - (match_operand:SI 2 "const_0_to_255_mul_8_operand" "n")))] - "TARGET_SSE2" -{ - operands[2] = GEN_INT (INTVAL (operands[2]) / 8); - return "pslldq\t{%2, %0|%0, %2}"; -} - [(set_attr "type" "sseishft") - (set_attr "prefix_data16" "1") - (set_attr "length_immediate" "1") - (set_attr "mode" "TI")]) - -(define_insn "*ashlti3_1" - [(set (match_operand:TI 0 "register_operand" "=&r,r") - (ashift:TI (match_operand:TI 1 "reg_or_pm1_operand" "n,0") - (match_operand:QI 2 "nonmemory_operand" "Oc,Oc"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -(define_peephole2 - [(match_scratch:DI 3 "r") - (parallel [(set (match_operand:TI 0 "register_operand" "") - (ashift:TI (match_operand:TI 1 "nonmemory_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) - (match_dup 3)] - "TARGET_64BIT" - [(const_int 0)] - "ix86_split_ashl (operands, operands[3], TImode); DONE;") - -(define_split - [(set (match_operand:TI 0 "register_operand" "") - (ashift:TI (match_operand:TI 1 "nonmemory_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? epilogue_completed : reload_completed)" - [(const_int 0)] - "ix86_split_ashl (operands, NULL_RTX, TImode); DONE;") - -(define_insn "x86_64_shld" - [(set (match_operand:DI 0 "nonimmediate_operand" "+r*m") - (ior:DI (ashift:DI (match_dup 0) - (match_operand:QI 2 "nonmemory_operand" "Jc")) - (lshiftrt:DI (match_operand:DI 1 "register_operand" "r") - (minus:QI (const_int 64) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "shld{q}\t{%s2%1, %0|%0, %1, %2}" - [(set_attr "type" "ishift") - (set_attr "prefix_0f" "1") - (set_attr "mode" "DI") - (set_attr "athlon_decode" "vector") - (set_attr "amdfam10_decode" "vector")]) - -(define_expand "x86_64_shift_adj_1" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (and:QI (match_operand:QI 2 "register_operand" "") - (const_int 64)) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "") - (if_then_else:DI (ne (reg:CCZ FLAGS_REG) (const_int 0)) - (match_operand:DI 1 "register_operand" "") - (match_dup 0))) - (set (match_dup 1) - (if_then_else:DI (ne (reg:CCZ FLAGS_REG) (const_int 0)) - (match_operand:DI 3 "register_operand" "r") - (match_dup 1)))] - "TARGET_64BIT" - "") - -(define_expand "x86_64_shift_adj_2" - [(use (match_operand:DI 0 "register_operand" "")) - (use (match_operand:DI 1 "register_operand" "")) - (use (match_operand:QI 2 "register_operand" ""))] - "TARGET_64BIT" -{ - rtx label = gen_label_rtx (); - rtx tmp; - - emit_insn (gen_testqi_ccz_1 (operands[2], GEN_INT (64))); - - tmp = gen_rtx_REG (CCZmode, FLAGS_REG); - tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); - tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, - gen_rtx_LABEL_REF (VOIDmode, label), - pc_rtx); - tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); - JUMP_LABEL (tmp) = label; - - emit_move_insn (operands[0], operands[1]); - ix86_expand_clear (operands[1]); - - emit_label (label); - LABEL_NUSES (label) = 1; - - DONE; -}) - -(define_expand "ashldi3" - [(set (match_operand:DI 0 "shiftdi_operand" "") - (ashift:DI (match_operand:DI 1 "ashldi_input_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - "ix86_expand_binary_operator (ASHIFT, DImode, operands); DONE;") - -(define_insn "*ashldi3_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") - (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0,l") - (match_operand:QI 2 "nonmemory_operand" "cJ,M"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (ASHIFT, DImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - gcc_assert (rtx_equal_p (operands[0], operands[1])); - return "add{q}\t%0, %0"; - - case TYPE_LEA: - gcc_assert (CONST_INT_P (operands[2])); - gcc_assert ((unsigned HOST_WIDE_INT) INTVAL (operands[2]) <= 3); - operands[1] = gen_rtx_MULT (DImode, operands[1], - GEN_INT (1 << INTVAL (operands[2]))); - return "lea{q}\t{%a1, %0|%0, %a1}"; - - default: - if (REG_P (operands[2])) - return "sal{q}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{q}\t%0"; - else - return "sal{q}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(eq_attr "alternative" "1") - (const_string "lea") - (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "DI")]) - -;; Convert lea to the lea pattern to avoid flags dependency. -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (ashift:DI (match_operand:DI 1 "index_register_operand" "") - (match_operand:QI 2 "immediate_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed - && true_regnum (operands[0]) != true_regnum (operands[1])" - [(set (match_dup 0) - (mult:DI (match_dup 1) - (match_dup 2)))] - "operands[2] = gen_int_mode (1 << INTVAL (operands[2]), DImode);") - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashldi3_cmp_rex64" - [(set (reg FLAGS_REG) - (compare - (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_63_operand" "J")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (ashift:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT - && (optimize_function_for_size_p (cfun) - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0]))))) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, DImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{q}\t%0, %0"; - - default: - if (REG_P (operands[2])) - return "sal{q}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{q}\t%0"; - else - return "sal{q}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "DI")]) - -(define_insn "*ashldi3_cconly_rex64" - [(set (reg FLAGS_REG) - (compare - (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_63_operand" "J")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT - && (optimize_function_for_size_p (cfun) - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || TARGET_DOUBLE_WITH_ADD))) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, DImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{q}\t%0, %0"; - - default: - if (REG_P (operands[2])) - return "sal{q}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{q}\t%0"; - else - return "sal{q}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "DI")]) - -(define_insn "*ashldi3_1" - [(set (match_operand:DI 0 "register_operand" "=&r,r") - (ashift:DI (match_operand:DI 1 "reg_or_pm1_operand" "n,0") - (match_operand:QI 2 "nonmemory_operand" "Jc,Jc"))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -;; By default we don't ask for a scratch register, because when DImode -;; values are manipulated, registers are already at a premium. But if -;; we have one handy, we won't turn it away. -(define_peephole2 - [(match_scratch:SI 3 "r") - (parallel [(set (match_operand:DI 0 "register_operand" "") - (ashift:DI (match_operand:DI 1 "nonmemory_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) - (match_dup 3)] - "!TARGET_64BIT && TARGET_CMOVE" - [(const_int 0)] - "ix86_split_ashl (operands, operands[3], DImode); DONE;") - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (ashift:DI (match_operand:DI 1 "nonmemory_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? epilogue_completed : reload_completed)" - [(const_int 0)] - "ix86_split_ashl (operands, NULL_RTX, DImode); DONE;") - -(define_insn "x86_shld" - [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m") - (ior:SI (ashift:SI (match_dup 0) - (match_operand:QI 2 "nonmemory_operand" "Ic")) - (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") - (minus:QI (const_int 32) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))] - "" - "shld{l}\t{%s2%1, %0|%0, %1, %2}" - [(set_attr "type" "ishift") - (set_attr "prefix_0f" "1") - (set_attr "mode" "SI") - (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector") - (set_attr "amdfam10_decode" "vector")]) - -(define_expand "x86_shift_adj_1" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (and:QI (match_operand:QI 2 "register_operand" "") - (const_int 32)) - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "") - (if_then_else:SI (ne (reg:CCZ FLAGS_REG) (const_int 0)) - (match_operand:SI 1 "register_operand" "") - (match_dup 0))) - (set (match_dup 1) - (if_then_else:SI (ne (reg:CCZ FLAGS_REG) (const_int 0)) - (match_operand:SI 3 "register_operand" "r") - (match_dup 1)))] - "TARGET_CMOVE" - "") - -(define_expand "x86_shift_adj_2" - [(use (match_operand:SI 0 "register_operand" "")) - (use (match_operand:SI 1 "register_operand" "")) - (use (match_operand:QI 2 "register_operand" ""))] - "" -{ - rtx label = gen_label_rtx (); - rtx tmp; - - emit_insn (gen_testqi_ccz_1 (operands[2], GEN_INT (32))); - - tmp = gen_rtx_REG (CCZmode, FLAGS_REG); - tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); - tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, - gen_rtx_LABEL_REF (VOIDmode, label), - pc_rtx); - tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); - JUMP_LABEL (tmp) = label; - - emit_move_insn (operands[0], operands[1]); - ix86_expand_clear (operands[1]); - - emit_label (label); - LABEL_NUSES (label) = 1; - - DONE; -}) - -(define_expand "ashlsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - "ix86_expand_binary_operator (ASHIFT, SImode, operands); DONE;") - -(define_insn "*ashlsi3_1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") - (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,l") - (match_operand:QI 2 "nonmemory_operand" "cI,M"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (ASHIFT, SImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - gcc_assert (rtx_equal_p (operands[0], operands[1])); - return "add{l}\t%0, %0"; - - case TYPE_LEA: - return "#"; - - default: - if (REG_P (operands[2])) - return "sal{l}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{l}\t%0"; - else - return "sal{l}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(eq_attr "alternative" "1") - (const_string "lea") - (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "SI")]) - -;; Convert lea to the lea pattern to avoid flags dependency. -(define_split - [(set (match_operand 0 "register_operand" "") - (ashift (match_operand 1 "index_register_operand" "") - (match_operand:QI 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "reload_completed - && true_regnum (operands[0]) != true_regnum (operands[1]) - && GET_MODE_SIZE (GET_MODE (operands[0])) <= 4" - [(const_int 0)] -{ - rtx pat; - enum machine_mode mode = GET_MODE (operands[0]); - - if (GET_MODE_SIZE (mode) < 4) - operands[0] = gen_lowpart (SImode, operands[0]); - if (mode != Pmode) - operands[1] = gen_lowpart (Pmode, operands[1]); - operands[2] = gen_int_mode (1 << INTVAL (operands[2]), Pmode); - - pat = gen_rtx_MULT (Pmode, operands[1], operands[2]); - if (Pmode != SImode) - pat = gen_rtx_SUBREG (SImode, pat, 0); - emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); - DONE; -}) - -;; Rare case of shifting RSP is handled by generating move and shift -(define_split - [(set (match_operand 0 "register_operand" "") - (ashift (match_operand 1 "register_operand" "") - (match_operand:QI 2 "const_int_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "reload_completed - && true_regnum (operands[0]) != true_regnum (operands[1])" - [(const_int 0)] -{ - rtx pat, clob; - emit_move_insn (operands[0], operands[1]); - pat = gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_ASHIFT (GET_MODE (operands[0]), - operands[0], operands[2])); - clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); - emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob))); - DONE; -}) - -(define_insn "*ashlsi3_1_zext" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (zero_extend:DI (ashift:SI (match_operand:SI 1 "register_operand" "0,l") - (match_operand:QI 2 "nonmemory_operand" "cI,M")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (ASHIFT, SImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{l}\t%k0, %k0"; - - case TYPE_LEA: - return "#"; - - default: - if (REG_P (operands[2])) - return "sal{l}\t{%b2, %k0|%k0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{l}\t%k0"; - else - return "sal{l}\t{%2, %k0|%k0, %2}"; - } -} - [(set (attr "type") - (cond [(eq_attr "alternative" "1") - (const_string "lea") - (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "SI")]) - -;; Convert lea to the lea pattern to avoid flags dependency. -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (zero_extend:DI (ashift (match_operand 1 "register_operand" "") - (match_operand:QI 2 "const_int_operand" "")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed - && true_regnum (operands[0]) != true_regnum (operands[1])" - [(set (match_dup 0) (zero_extend:DI - (subreg:SI (mult:SI (match_dup 1) - (match_dup 2)) 0)))] -{ - operands[1] = gen_lowpart (Pmode, operands[1]); - operands[2] = gen_int_mode (1 << INTVAL (operands[2]), Pmode); -}) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashlsi3_cmp" - [(set (reg FLAGS_REG) - (compare - (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (ashift:SI (match_dup 1) (match_dup 2)))] - "(optimize_function_for_size_p (cfun) - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0]))))) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, SImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{l}\t%0, %0"; - - default: - if (REG_P (operands[2])) - return "sal{l}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{l}\t%0"; - else - return "sal{l}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "SI")]) - -(define_insn "*ashlsi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "(optimize_function_for_size_p (cfun) - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || TARGET_DOUBLE_WITH_ADD))) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, SImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{l}\t%0, %0"; - - default: - if (REG_P (operands[2])) - return "sal{l}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{l}\t%0"; - else - return "sal{l}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "SI")]) - -(define_insn "*ashlsi3_cmp_zext" - [(set (reg FLAGS_REG) - (compare - (ashift:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (ashift:SI (match_dup 1) (match_dup 2))))] - "TARGET_64BIT - && (optimize_function_for_size_p (cfun) - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || TARGET_DOUBLE_WITH_ADD))) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, SImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{l}\t%k0, %k0"; - - default: - if (REG_P (operands[2])) - return "sal{l}\t{%b2, %k0|%k0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{l}\t%k0"; - else - return "sal{l}\t{%2, %k0|%k0, %2}"; - } -} - [(set (attr "type") - (cond [(and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "SI")]) - -(define_expand "ashlhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_binary_operator (ASHIFT, HImode, operands); DONE;") - -(define_insn "*ashlhi3_1_lea" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") - (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0,l") - (match_operand:QI 2 "nonmemory_operand" "cI,M"))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_PARTIAL_REG_STALL - && ix86_binary_operator_ok (ASHIFT, HImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_LEA: - return "#"; - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{w}\t%0, %0"; - - default: - if (REG_P (operands[2])) - return "sal{w}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{w}\t%0"; - else - return "sal{w}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(eq_attr "alternative" "1") - (const_string "lea") - (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "HI,SI")]) - -(define_insn "*ashlhi3_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "nonmemory_operand" "cI"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_PARTIAL_REG_STALL - && ix86_binary_operator_ok (ASHIFT, HImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{w}\t%0, %0"; - - default: - if (REG_P (operands[2])) - return "sal{w}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{w}\t%0"; - else - return "sal{w}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "HI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashlhi3_cmp" - [(set (reg FLAGS_REG) - (compare - (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (ashift:HI (match_dup 1) (match_dup 2)))] - "(optimize_function_for_size_p (cfun) - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0]))))) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, HImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{w}\t%0, %0"; - - default: - if (REG_P (operands[2])) - return "sal{w}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{w}\t%0"; - else - return "sal{w}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "HI")]) - -(define_insn "*ashlhi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "(optimize_function_for_size_p (cfun) - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || TARGET_DOUBLE_WITH_ADD))) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, HImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{w}\t%0, %0"; - - default: - if (REG_P (operands[2])) - return "sal{w}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{w}\t%0"; - else - return "sal{w}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "HI")]) - -(define_expand "ashlqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_binary_operator (ASHIFT, QImode, operands); DONE;") - -;; %%% Potential partial reg stall on alternative 2. What to do? - -(define_insn "*ashlqi3_1_lea" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r,r") - (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0,l") - (match_operand:QI 2 "nonmemory_operand" "cI,cI,M"))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_PARTIAL_REG_STALL - && ix86_binary_operator_ok (ASHIFT, QImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_LEA: - return "#"; - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - if (REG_P (operands[1]) && !ANY_QI_REG_P (operands[1])) - return "add{l}\t%k0, %k0"; - else - return "add{b}\t%0, %0"; - - default: - if (REG_P (operands[2])) - { - if (get_attr_mode (insn) == MODE_SI) - return "sal{l}\t{%b2, %k0|%k0, %b2}"; - else - return "sal{b}\t{%b2, %0|%0, %b2}"; - } - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - { - if (get_attr_mode (insn) == MODE_SI) - return "sal{l}\t%0"; - else - return "sal{b}\t%0"; - } - else - { - if (get_attr_mode (insn) == MODE_SI) - return "sal{l}\t{%2, %k0|%k0, %2}"; - else - return "sal{b}\t{%2, %0|%0, %2}"; - } - } -} - [(set (attr "type") - (cond [(eq_attr "alternative" "2") - (const_string "lea") - (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "QI,SI,SI")]) - -(define_insn "*ashlqi3_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r") - (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "cI,cI"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_PARTIAL_REG_STALL - && ix86_binary_operator_ok (ASHIFT, QImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - if (REG_P (operands[1]) && !ANY_QI_REG_P (operands[1])) - return "add{l}\t%k0, %k0"; - else - return "add{b}\t%0, %0"; - - default: - if (REG_P (operands[2])) - { - if (get_attr_mode (insn) == MODE_SI) - return "sal{l}\t{%b2, %k0|%k0, %b2}"; - else - return "sal{b}\t{%b2, %0|%0, %b2}"; - } - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - { - if (get_attr_mode (insn) == MODE_SI) - return "sal{l}\t%0"; - else - return "sal{b}\t%0"; - } - else - { - if (get_attr_mode (insn) == MODE_SI) - return "sal{l}\t{%2, %k0|%k0, %2}"; - else - return "sal{b}\t{%2, %0|%0, %2}"; - } - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "QI,SI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashlqi3_cmp" - [(set (reg FLAGS_REG) - (compare - (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (ashift:QI (match_dup 1) (match_dup 2)))] - "(optimize_function_for_size_p (cfun) - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0]))))) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, QImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{b}\t%0, %0"; - - default: - if (REG_P (operands[2])) - return "sal{b}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{b}\t%0"; - else - return "sal{b}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "QI")]) - -(define_insn "*ashlqi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "(optimize_function_for_size_p (cfun) - || !TARGET_PARTIAL_FLAG_REG_STALL - || (operands[2] == const1_rtx - && (TARGET_SHIFT1 - || TARGET_DOUBLE_WITH_ADD))) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFT, QImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_ALU: - gcc_assert (operands[2] == const1_rtx); - return "add{b}\t%0, %0"; - - default: - if (REG_P (operands[2])) - return "sal{b}\t{%b2, %0|%0, %b2}"; - else if (operands[2] == const1_rtx - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) - return "sal{b}\t%0"; - else - return "sal{b}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") - (const_int 0)) - (match_operand 0 "register_operand" "")) - (match_operand 2 "const1_operand" "")) - (const_string "alu") - ] - (const_string "ishift"))) - (set (attr "length_immediate") - (if_then_else - (ior (eq_attr "type" "alu") - (and (eq_attr "type" "ishift") - (and (match_operand 2 "const1_operand" "") - (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") - (const_int 0))))) - (const_string "0") - (const_string "*"))) - (set_attr "mode" "QI")]) - -;; See comment above `ashldi3' about how this works. - -(define_expand "ashrti3" - [(set (match_operand:TI 0 "register_operand" "") - (ashiftrt:TI (match_operand:TI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_64BIT" - "ix86_expand_binary_operator (ASHIFTRT, TImode, operands); DONE;") - -(define_insn "*ashrti3_1" - [(set (match_operand:TI 0 "register_operand" "=r") - (ashiftrt:TI (match_operand:TI 1 "register_operand" "0") - (match_operand:QI 2 "nonmemory_operand" "Oc"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -(define_peephole2 - [(match_scratch:DI 3 "r") - (parallel [(set (match_operand:TI 0 "register_operand" "") - (ashiftrt:TI (match_operand:TI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) - (match_dup 3)] - "TARGET_64BIT" - [(const_int 0)] - "ix86_split_ashr (operands, operands[3], TImode); DONE;") - -(define_split - [(set (match_operand:TI 0 "register_operand" "") - (ashiftrt:TI (match_operand:TI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? epilogue_completed : reload_completed)" - [(const_int 0)] - "ix86_split_ashr (operands, NULL_RTX, TImode); DONE;") - -(define_insn "x86_64_shrd" - [(set (match_operand:DI 0 "nonimmediate_operand" "+r*m") - (ior:DI (ashiftrt:DI (match_dup 0) - (match_operand:QI 2 "nonmemory_operand" "Jc")) - (ashift:DI (match_operand:DI 1 "register_operand" "r") - (minus:QI (const_int 64) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "shrd{q}\t{%s2%1, %0|%0, %1, %2}" - [(set_attr "type" "ishift") - (set_attr "prefix_0f" "1") - (set_attr "mode" "DI") - (set_attr "athlon_decode" "vector") - (set_attr "amdfam10_decode" "vector")]) - -(define_expand "ashrdi3" - [(set (match_operand:DI 0 "shiftdi_operand" "") - (ashiftrt:DI (match_operand:DI 1 "shiftdi_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - "ix86_expand_binary_operator (ASHIFTRT, DImode, operands); DONE;") - -(define_expand "x86_64_shift_adj_3" - [(use (match_operand:DI 0 "register_operand" "")) - (use (match_operand:DI 1 "register_operand" "")) - (use (match_operand:QI 2 "register_operand" ""))] - "" -{ - rtx label = gen_label_rtx (); - rtx tmp; - - emit_insn (gen_testqi_ccz_1 (operands[2], GEN_INT (64))); - - tmp = gen_rtx_REG (CCZmode, FLAGS_REG); - tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); - tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, - gen_rtx_LABEL_REF (VOIDmode, label), - pc_rtx); - tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); - JUMP_LABEL (tmp) = label; - - emit_move_insn (operands[0], operands[1]); - emit_insn (gen_ashrdi3_63_rex64 (operands[1], operands[1], GEN_INT (63))); - - emit_label (label); - LABEL_NUSES (label) = 1; - - DONE; -}) - -(define_insn "ashrdi3_63_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=*d,rm") - (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "*a,0") - (match_operand:DI 2 "const_int_operand" "i,i"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && INTVAL (operands[2]) == 63 - && (TARGET_USE_CLTD || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" - "@ - {cqto|cqo} - sar{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "imovx,ishift") - (set_attr "prefix_0f" "0,*") - (set_attr "length_immediate" "0,*") - (set_attr "modrm" "0,1") - (set_attr "mode" "DI")]) - -(define_insn "*ashrdi3_1_one_bit_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" - "sar{q}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "DI")]) - -(define_insn "*ashrdi3_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") - (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "J,c"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" - "@ - sar{q}\t{%2, %0|%0, %2} - sar{q}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "ishift") - (set_attr "mode" "DI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashrdi3_one_bit_cmp_rex64" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (ashiftrt:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" - "sar{q}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "DI")]) - -(define_insn "*ashrdi3_one_bit_cconly_rex64" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" - "sar{q}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "DI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashrdi3_cmp_rex64" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_63_operand" "J")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (ashiftrt:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT - && (optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" - "sar{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "DI")]) - -(define_insn "*ashrdi3_cconly_rex64" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_63_operand" "J")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT - && (optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" - "sar{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "DI")]) - -(define_insn "*ashrdi3_1" - [(set (match_operand:DI 0 "register_operand" "=r") - (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:QI 2 "nonmemory_operand" "Jc"))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -;; By default we don't ask for a scratch register, because when DImode -;; values are manipulated, registers are already at a premium. But if -;; we have one handy, we won't turn it away. -(define_peephole2 - [(match_scratch:SI 3 "r") - (parallel [(set (match_operand:DI 0 "register_operand" "") - (ashiftrt:DI (match_operand:DI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) - (match_dup 3)] - "!TARGET_64BIT && TARGET_CMOVE" - [(const_int 0)] - "ix86_split_ashr (operands, operands[3], DImode); DONE;") - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (ashiftrt:DI (match_operand:DI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? epilogue_completed : reload_completed)" - [(const_int 0)] - "ix86_split_ashr (operands, NULL_RTX, DImode); DONE;") - -(define_insn "x86_shrd" - [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m") - (ior:SI (ashiftrt:SI (match_dup 0) - (match_operand:QI 2 "nonmemory_operand" "Ic")) - (ashift:SI (match_operand:SI 1 "register_operand" "r") - (minus:QI (const_int 32) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))] - "" - "shrd{l}\t{%s2%1, %0|%0, %1, %2}" - [(set_attr "type" "ishift") - (set_attr "prefix_0f" "1") - (set_attr "pent_pair" "np") - (set_attr "mode" "SI")]) - -(define_expand "x86_shift_adj_3" - [(use (match_operand:SI 0 "register_operand" "")) - (use (match_operand:SI 1 "register_operand" "")) - (use (match_operand:QI 2 "register_operand" ""))] - "" -{ - rtx label = gen_label_rtx (); - rtx tmp; - - emit_insn (gen_testqi_ccz_1 (operands[2], GEN_INT (32))); - - tmp = gen_rtx_REG (CCZmode, FLAGS_REG); - tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); - tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, - gen_rtx_LABEL_REF (VOIDmode, label), - pc_rtx); - tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); - JUMP_LABEL (tmp) = label; - - emit_move_insn (operands[0], operands[1]); - emit_insn (gen_ashrsi3_31 (operands[1], operands[1], GEN_INT (31))); - - emit_label (label); - LABEL_NUSES (label) = 1; - - DONE; -}) - -(define_expand "ashrsi3_31" - [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "=*d,rm") - (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "*a,0") - (match_operand:SI 2 "const_int_operand" "i,i"))) - (clobber (reg:CC FLAGS_REG))])] - "") - -(define_insn "*ashrsi3_31" - [(set (match_operand:SI 0 "nonimmediate_operand" "=*d,rm") - (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "*a,0") - (match_operand:SI 2 "const_int_operand" "i,i"))) - (clobber (reg:CC FLAGS_REG))] - "INTVAL (operands[2]) == 31 - && (TARGET_USE_CLTD || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "@ - {cltd|cdq} - sar{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "imovx,ishift") - (set_attr "prefix_0f" "0,*") - (set_attr "length_immediate" "0,*") - (set_attr "modrm" "0,1") - (set_attr "mode" "SI")]) - -(define_insn "*ashrsi3_31_zext" - [(set (match_operand:DI 0 "register_operand" "=*d,r") - (zero_extend:DI (ashiftrt:SI (match_operand:SI 1 "register_operand" "*a,0") - (match_operand:SI 2 "const_int_operand" "i,i")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && (TARGET_USE_CLTD || optimize_function_for_size_p (cfun)) - && INTVAL (operands[2]) == 31 - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "@ - {cltd|cdq} - sar{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "imovx,ishift") - (set_attr "prefix_0f" "0,*") - (set_attr "length_immediate" "0,*") - (set_attr "modrm" "0,1") - (set_attr "mode" "SI")]) - -(define_expand "ashrsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - "ix86_expand_binary_operator (ASHIFTRT, SImode, operands); DONE;") - -(define_insn "*ashrsi3_1_one_bit" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "sar{l}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) - -(define_insn "*ashrsi3_1_one_bit_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const1_operand" "")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "sar{l}\t%k0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) - -(define_insn "*ashrsi3_1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") - (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "@ - sar{l}\t{%2, %0|%0, %2} - sar{l}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) - -(define_insn "*ashrsi3_1_zext" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (zero_extend:DI (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "@ - sar{l}\t{%2, %k0|%k0, %2} - sar{l}\t{%b2, %k0|%k0, %b2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashrsi3_one_bit_cmp" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (ashiftrt:SI (match_dup 1) (match_dup 2)))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "sar{l}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) - -(define_insn "*ashrsi3_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "sar{l}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) - -(define_insn "*ashrsi3_one_bit_cmp_zext" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (ashiftrt:SI (match_dup 1) (match_dup 2))))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCmode) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "sar{l}\t%k0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashrsi3_cmp" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (ashiftrt:SI (match_dup 1) (match_dup 2)))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "sar{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) - -(define_insn "*ashrsi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "sar{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) - -(define_insn "*ashrsi3_cmp_zext" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (ashiftrt:SI (match_dup 1) (match_dup 2))))] - "TARGET_64BIT - && (optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" - "sar{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) - -(define_expand "ashrhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_binary_operator (ASHIFTRT, HImode, operands); DONE;") - -(define_insn "*ashrhi3_1_one_bit" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" - "sar{w}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "HI")]) - -(define_insn "*ashrhi3_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") - (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" - "@ - sar{w}\t{%2, %0|%0, %2} - sar{w}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "ishift") - (set_attr "mode" "HI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashrhi3_one_bit_cmp" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (ashiftrt:HI (match_dup 1) (match_dup 2)))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" - "sar{w}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "HI")]) - -(define_insn "*ashrhi3_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" - "sar{w}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "HI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashrhi3_cmp" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (ashiftrt:HI (match_dup 1) (match_dup 2)))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" - "sar{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "HI")]) - -(define_insn "*ashrhi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)" - "sar{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "HI")]) - -(define_expand "ashrqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_binary_operator (ASHIFTRT, QImode, operands); DONE;") - -(define_insn "*ashrqi3_1_one_bit" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" - "sar{b}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) - -(define_insn "*ashrqi3_1_one_bit_slp" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) - (ashiftrt:QI (match_dup 0) - (match_operand:QI 1 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" - "sar{b}\t%0" - [(set_attr "type" "ishift1") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) - -(define_insn "*ashrqi3_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") - (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" - "@ - sar{b}\t{%2, %0|%0, %2} - sar{b}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "ishift") - (set_attr "mode" "QI")]) - -(define_insn "*ashrqi3_1_slp" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,qm")) - (ashiftrt:QI (match_dup 0) - (match_operand:QI 1 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "@ - sar{b}\t{%1, %0|%0, %1} - sar{b}\t{%b1, %0|%0, %b1}" - [(set_attr "type" "ishift1") - (set_attr "mode" "QI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashrqi3_one_bit_cmp" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "I")) - (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (ashiftrt:QI (match_dup 1) (match_dup 2)))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" - "sar{b}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) - -(define_insn "*ashrqi3_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" - "sar{b}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*ashrqi3_cmp" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (ashiftrt:QI (match_dup 1) (match_dup 2)))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" - "sar{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "QI")]) - -(define_insn "*ashrqi3_cconly" - [(set (reg FLAGS_REG) - (compare - (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)" - "sar{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "QI")]) - - -;; Logical shift instructions - -;; See comment above `ashldi3' about how this works. - -(define_expand "lshrti3" - [(set (match_operand:TI 0 "register_operand" "") - (lshiftrt:TI (match_operand:TI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_64BIT" - "ix86_expand_binary_operator (LSHIFTRT, TImode, operands); DONE;") - -;; This pattern must be defined before *lshrti3_1 to prevent -;; combine pass from converting sse2_lshrti3 to *lshrti3_1. - -(define_insn "*avx_lshrti3" - [(set (match_operand:TI 0 "register_operand" "=x") - (lshiftrt:TI (match_operand:TI 1 "register_operand" "x") - (match_operand:SI 2 "const_0_to_255_mul_8_operand" "n")))] - "TARGET_AVX" -{ - operands[2] = GEN_INT (INTVAL (operands[2]) / 8); - return "vpsrldq\t{%2, %1, %0|%0, %1, %2}"; -} - [(set_attr "type" "sseishft") - (set_attr "prefix" "vex") - (set_attr "length_immediate" "1") - (set_attr "mode" "TI")]) - -(define_insn "sse2_lshrti3" - [(set (match_operand:TI 0 "register_operand" "=x") - (lshiftrt:TI (match_operand:TI 1 "register_operand" "0") - (match_operand:SI 2 "const_0_to_255_mul_8_operand" "n")))] - "TARGET_SSE2" -{ - operands[2] = GEN_INT (INTVAL (operands[2]) / 8); - return "psrldq\t{%2, %0|%0, %2}"; -} - [(set_attr "type" "sseishft") - (set_attr "prefix_data16" "1") - (set_attr "length_immediate" "1") - (set_attr "mode" "TI")]) - -(define_insn "*lshrti3_1" - [(set (match_operand:TI 0 "register_operand" "=r") - (lshiftrt:TI (match_operand:TI 1 "register_operand" "0") - (match_operand:QI 2 "nonmemory_operand" "Oc"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -(define_peephole2 - [(match_scratch:DI 3 "r") - (parallel [(set (match_operand:TI 0 "register_operand" "") - (lshiftrt:TI (match_operand:TI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) - (match_dup 3)] - "TARGET_64BIT" - [(const_int 0)] - "ix86_split_lshr (operands, operands[3], TImode); DONE;") - -(define_split - [(set (match_operand:TI 0 "register_operand" "") - (lshiftrt:TI (match_operand:TI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? epilogue_completed : reload_completed)" - [(const_int 0)] - "ix86_split_lshr (operands, NULL_RTX, TImode); DONE;") - -(define_expand "lshrdi3" - [(set (match_operand:DI 0 "shiftdi_operand" "") - (lshiftrt:DI (match_operand:DI 1 "shiftdi_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - "ix86_expand_binary_operator (LSHIFTRT, DImode, operands); DONE;") - -(define_insn "*lshrdi3_1_one_bit_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{q}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "DI")]) - -(define_insn "*lshrdi3_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") - (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "J,c"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "@ - shr{q}\t{%2, %0|%0, %2} - shr{q}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "ishift") - (set_attr "mode" "DI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*lshrdi3_cmp_one_bit_rex64" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (lshiftrt:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{q}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "DI")]) - -(define_insn "*lshrdi3_cconly_one_bit_rex64" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{q}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "DI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*lshrdi3_cmp_rex64" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_63_operand" "J")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (lshiftrt:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT - && (optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "DI")]) - -(define_insn "*lshrdi3_cconly_rex64" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_63_operand" "J")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT - && (optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "DI")]) - -(define_insn "*lshrdi3_1" - [(set (match_operand:DI 0 "register_operand" "=r") - (lshiftrt:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:QI 2 "nonmemory_operand" "Jc"))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT" - "#" - [(set_attr "type" "multi")]) - -;; By default we don't ask for a scratch register, because when DImode -;; values are manipulated, registers are already at a premium. But if -;; we have one handy, we won't turn it away. -(define_peephole2 - [(match_scratch:SI 3 "r") - (parallel [(set (match_operand:DI 0 "register_operand" "") - (lshiftrt:DI (match_operand:DI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))]) - (match_dup 3)] - "!TARGET_64BIT && TARGET_CMOVE" - [(const_int 0)] - "ix86_split_lshr (operands, operands[3], DImode); DONE;") - -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (lshiftrt:DI (match_operand:DI 1 "register_operand" "") - (match_operand:QI 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && ((optimize > 0 && flag_peephole2) - ? epilogue_completed : reload_completed)" - [(const_int 0)] - "ix86_split_lshr (operands, NULL_RTX, DImode); DONE;") - -(define_expand "lshrsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - "ix86_expand_binary_operator (LSHIFTRT, SImode, operands); DONE;") + case TYPE_ALU: + gcc_assert (operands[2] == const1_rtx); + return "add{w}\t%0, %0"; -(define_insn "*lshrsi3_1_one_bit" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{l}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) + default: + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "sal{w}\t%0"; + else + return "sal{w}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "1") + (const_string "lea") + (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set (attr "length_immediate") + (if_then_else + (ior (eq_attr "type" "alu") + (and (eq_attr "type" "ishift") + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "HI,SI")]) -(define_insn "*lshrsi3_1_one_bit_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (lshiftrt:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "0")) - (match_operand:QI 2 "const1_operand" ""))) +(define_insn "*ashlqi3_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") + (match_operand:QI 2 "nonmemory_operand" "cI,cI"))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{l}\t%k0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) + "TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (ASHIFT, QImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_ALU: + gcc_assert (operands[2] == const1_rtx); + if (REG_P (operands[1]) && !ANY_QI_REG_P (operands[1])) + return "add{l}\t%k0, %k0"; + else + return "add{b}\t%0, %0"; -(define_insn "*lshrsi3_1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") - (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "@ - shr{l}\t{%2, %0|%0, %2} - shr{l}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) + default: + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + { + if (get_attr_mode (insn) == MODE_SI) + return "sal{l}\t%k0"; + else + return "sal{b}\t%0"; + } + else + { + if (get_attr_mode (insn) == MODE_SI) + return "sal{l}\t{%2, %k0|%k0, %2}"; + else + return "sal{b}\t{%2, %0|%0, %2}"; + } + } +} + [(set (attr "type") + (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set (attr "length_immediate") + (if_then_else + (ior (eq_attr "type" "alu") + (and (eq_attr "type" "ishift") + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "QI,SI")]) -(define_insn "*lshrsi3_1_zext" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (zero_extend:DI - (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c")))) +;; %%% Potential partial reg stall on alternative 2. What to do? +(define_insn "*ashlqi3_1_lea" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r,r") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0,l") + (match_operand:QI 2 "nonmemory_operand" "cI,cI,M"))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "@ - shr{l}\t{%2, %k0|%k0, %2} - shr{l}\t{%b2, %k0|%k0, %b2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*lshrsi3_one_bit_cmp" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (lshiftrt:SI (match_dup 1) (match_dup 2)))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{l}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) - -(define_insn "*lshrsi3_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{l}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) - -(define_insn "*lshrsi3_cmp_one_bit_zext" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (lshiftrt:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{l}\t%k0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) + "!TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (ASHIFT, QImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_LEA: + return "#"; -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*lshrsi3_cmp" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (lshiftrt:SI (match_dup 1) (match_dup 2)))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) + case TYPE_ALU: + gcc_assert (operands[2] == const1_rtx); + if (REG_P (operands[1]) && !ANY_QI_REG_P (operands[1])) + return "add{l}\t%k0, %k0"; + else + return "add{b}\t%0, %0"; -(define_insn "*lshrsi3_cconly" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) + default: + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + { + if (get_attr_mode (insn) == MODE_SI) + return "sal{l}\t%k0"; + else + return "sal{b}\t%0"; + } + else + { + if (get_attr_mode (insn) == MODE_SI) + return "sal{l}\t{%2, %k0|%k0, %2}"; + else + return "sal{b}\t{%2, %0|%0, %2}"; + } + } +} + [(set (attr "type") + (cond [(eq_attr "alternative" "2") + (const_string "lea") + (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set (attr "length_immediate") + (if_then_else + (ior (eq_attr "type" "alu") + (and (eq_attr "type" "ishift") + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "QI,SI,SI")]) -(define_insn "*lshrsi3_cmp_zext" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (lshiftrt:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))] - "TARGET_64BIT - && (optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "SI")]) +(define_insn "*ashlqi3_1_slp" + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) + (ashift:QI (match_dup 0) + (match_operand:QI 1 "nonmemory_operand" "cI"))) + (clobber (reg:CC FLAGS_REG))] + "(optimize_function_for_size_p (cfun) + || !TARGET_PARTIAL_FLAG_REG_STALL + || (operands[1] == const1_rtx + && (TARGET_SHIFT1 + || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0])))))" +{ + switch (get_attr_type (insn)) + { + case TYPE_ALU: + gcc_assert (operands[1] == const1_rtx); + return "add{b}\t%0, %0"; -(define_expand "lshrhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_binary_operator (LSHIFTRT, HImode, operands); DONE;") + default: + if (operands[1] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "sal{b}\t%0"; + else + return "sal{b}\t{%1, %0|%0, %1}"; + } +} + [(set (attr "type") + (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 1 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift1"))) + (set (attr "length_immediate") + (if_then_else + (ior (eq_attr "type" "alu") + (and (eq_attr "type" "ishift1") + (and (match_operand 1 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "QI")]) -(define_insn "*lshrhi3_1_one_bit" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) +;; Convert lea to the lea pattern to avoid flags dependency. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (ashift:DI (match_operand:DI 1 "index_register_operand" "") + (match_operand:QI 2 "const_int_operand" ""))) (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{w}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "HI")]) + "TARGET_64BIT && reload_completed + && true_regnum (operands[0]) != true_regnum (operands[1])" + [(set (match_dup 0) + (mult:DI (match_dup 1) + (match_dup 2)))] + "operands[2] = gen_int_mode (1 << INTVAL (operands[2]), DImode);") -(define_insn "*lshrhi3_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") - (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) +;; Convert lea to the lea pattern to avoid flags dependency. +(define_split + [(set (match_operand 0 "register_operand" "") + (ashift (match_operand 1 "index_register_operand" "") + (match_operand:QI 2 "const_int_operand" ""))) (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "@ - shr{w}\t{%2, %0|%0, %2} - shr{w}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "ishift") - (set_attr "mode" "HI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*lshrhi3_one_bit_cmp" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (lshiftrt:HI (match_dup 1) (match_dup 2)))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{w}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "HI")]) - -(define_insn "*lshrhi3_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{w}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "HI")]) - -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*lshrhi3_cmp" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (lshiftrt:HI (match_dup 1) (match_dup 2)))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "HI")]) - -(define_insn "*lshrhi3_cconly" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) - (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)" - "shr{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "HI")]) - -(define_expand "lshrqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_binary_operator (LSHIFTRT, QImode, operands); DONE;") + "reload_completed + && true_regnum (operands[0]) != true_regnum (operands[1]) + && GET_MODE_SIZE (GET_MODE (operands[0])) <= 4" + [(const_int 0)] +{ + rtx pat; + enum machine_mode mode = GET_MODE (operands[0]); -(define_insn "*lshrqi3_1_one_bit" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" - "shr{b}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) + if (GET_MODE_SIZE (mode) < 4) + operands[0] = gen_lowpart (SImode, operands[0]); + if (mode != Pmode) + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = gen_int_mode (1 << INTVAL (operands[2]), Pmode); -(define_insn "*lshrqi3_1_one_bit_slp" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) - (lshiftrt:QI (match_dup 0) - (match_operand:QI 1 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))" - "shr{b}\t%0" - [(set_attr "type" "ishift1") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) + pat = gen_rtx_MULT (Pmode, operands[1], operands[2]); + if (Pmode != SImode) + pat = gen_rtx_SUBREG (SImode, pat, 0); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); + DONE; +}) -(define_insn "*lshrqi3_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") - (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) +;; Rare case of shifting RSP is handled by generating move and shift +(define_split + [(set (match_operand 0 "register_operand" "") + (ashift (match_operand 1 "register_operand" "") + (match_operand:QI 2 "const_int_operand" ""))) (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" - "@ - shr{b}\t{%2, %0|%0, %2} - shr{b}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "ishift") - (set_attr "mode" "QI")]) + "reload_completed + && true_regnum (operands[0]) != true_regnum (operands[1])" + [(const_int 0)] +{ + rtx pat, clob; + emit_move_insn (operands[0], operands[1]); + pat = gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_ASHIFT (GET_MODE (operands[0]), + operands[0], operands[2])); + clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); + emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob))); + DONE; +}) -(define_insn "*lshrqi3_1_slp" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,qm")) - (lshiftrt:QI (match_dup 0) - (match_operand:QI 1 "nonmemory_operand" "I,c"))) +;; Convert lea to the lea pattern to avoid flags dependency. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI + (ashift:SI (match_operand:SI 1 "register_operand" "") + (match_operand:QI 2 "const_int_operand" "")))) (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "@ - shr{b}\t{%1, %0|%0, %1} - shr{b}\t{%b1, %0|%0, %b1}" - [(set_attr "type" "ishift1") - (set_attr "mode" "QI")]) + "TARGET_64BIT && reload_completed + && true_regnum (operands[0]) != true_regnum (operands[1])" + [(set (match_dup 0) + (zero_extend:DI (subreg:SI (mult:DI (match_dup 1) (match_dup 2)) 0)))] +{ + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = gen_int_mode (1 << INTVAL (operands[2]), Pmode); +}) ;; This pattern can't accept a variable shift count, since shifts by ;; zero don't affect the flags. We assume that shifts by constant ;; zero are optimized away. -(define_insn "*lshrqi2_one_bit_cmp" +(define_insn "*ashl3_cmp" [(set (reg FLAGS_REG) (compare - (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) + (ashift:SWI (match_operand:SWI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "" "")) (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (lshiftrt:QI (match_dup 1) (match_dup 2)))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) + (set (match_operand:SWI 0 "nonimmediate_operand" "=m") + (ashift:SWI (match_dup 1) (match_dup 2)))] + "(optimize_function_for_size_p (cfun) + || !TARGET_PARTIAL_FLAG_REG_STALL + || (operands[2] == const1_rtx + && (TARGET_SHIFT1 + || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0]))))) && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" - "shr{b}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) + && ix86_binary_operator_ok (ASHIFT, mode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_ALU: + gcc_assert (operands[2] == const1_rtx); + return "add{}\t%0, %0"; -(define_insn "*lshrqi2_one_bit_cconly" - [(set (reg FLAGS_REG) - (compare - (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" "")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" - "shr{b}\t%0" - [(set_attr "type" "ishift") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) + default: + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "sal{}\t%0"; + else + return "sal{}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set (attr "length_immediate") + (if_then_else + (ior (eq_attr "type" "alu") + (and (eq_attr "type" "ishift") + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "")]) -;; This pattern can't accept a variable shift count, since shifts by -;; zero don't affect the flags. We assume that shifts by constant -;; zero are optimized away. -(define_insn "*lshrqi2_cmp" +(define_insn "*ashlsi3_cmp_zext" [(set (reg FLAGS_REG) (compare - (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "const_1_to_31_operand" "I")) (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (lshiftrt:QI (match_dup 1) (match_dup 2)))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (ashift:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT + && (optimize_function_for_size_p (cfun) + || !TARGET_PARTIAL_FLAG_REG_STALL + || (operands[2] == const1_rtx + && (TARGET_SHIFT1 + || TARGET_DOUBLE_WITH_ADD))) && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" - "shr{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "QI")]) + && ix86_binary_operator_ok (ASHIFT, SImode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_ALU: + gcc_assert (operands[2] == const1_rtx); + return "add{l}\t%k0, %k0"; + + default: + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "sal{l}\t%k0"; + else + return "sal{l}\t{%2, %k0|%k0, %2}"; + } +} + [(set (attr "type") + (cond [(and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set (attr "length_immediate") + (if_then_else + (ior (eq_attr "type" "alu") + (and (eq_attr "type" "ishift") + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "SI")]) -(define_insn "*lshrqi2_cconly" +(define_insn "*ashl3_cconly" [(set (reg FLAGS_REG) (compare - (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (ashift:SWI (match_operand:SWI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "" "")) (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "(optimize_function_for_size_p (cfun) || !TARGET_PARTIAL_FLAG_REG_STALL) + (clobber (match_scratch:SWI 0 "="))] + "(optimize_function_for_size_p (cfun) + || !TARGET_PARTIAL_FLAG_REG_STALL + || (operands[2] == const1_rtx + && (TARGET_SHIFT1 + || TARGET_DOUBLE_WITH_ADD))) && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)" - "shr{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "ishift") - (set_attr "mode" "QI")]) - -;; Rotate instructions - -(define_expand "rotldi3" - [(set (match_operand:DI 0 "shiftdi_operand" "") - (rotate:DI (match_operand:DI 1 "shiftdi_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" + && ix86_binary_operator_ok (ASHIFT, mode, operands)" { - if (TARGET_64BIT) + switch (get_attr_type (insn)) { - ix86_expand_binary_operator (ROTATE, DImode, operands); - DONE; + case TYPE_ALU: + gcc_assert (operands[2] == const1_rtx); + return "add{}\t%0, %0"; + + default: + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "sal{}\t%0"; + else + return "sal{}\t{%2, %0|%0, %2}"; } - if (!const_1_to_31_operand (operands[2], VOIDmode)) - FAIL; - emit_insn (gen_ix86_rotldi3 (operands[0], operands[1], operands[2])); - DONE; -}) +} + [(set (attr "type") + (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD") + (const_int 0)) + (match_operand 0 "register_operand" "")) + (match_operand 2 "const1_operand" "")) + (const_string "alu") + ] + (const_string "ishift"))) + (set (attr "length_immediate") + (if_then_else + (ior (eq_attr "type" "alu") + (and (eq_attr "type" "ishift") + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "")]) -;; Implement rotation using two double-precision shift instructions -;; and a scratch register. -(define_insn_and_split "ix86_rotldi3" - [(set (match_operand:DI 0 "register_operand" "=r") - (rotate:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I"))) - (clobber (reg:CC FLAGS_REG)) - (clobber (match_scratch:SI 3 "=&r"))] - "!TARGET_64BIT" - "" - "&& reload_completed" - [(set (match_dup 3) (match_dup 4)) - (parallel - [(set (match_dup 4) - (ior:SI (ashift:SI (match_dup 4) (match_dup 2)) - (lshiftrt:SI (match_dup 5) - (minus:QI (const_int 32) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))]) - (parallel - [(set (match_dup 5) - (ior:SI (ashift:SI (match_dup 5) (match_dup 2)) - (lshiftrt:SI (match_dup 3) - (minus:QI (const_int 32) (match_dup 2))))) - (clobber (reg:CC FLAGS_REG))])] - "split_di (&operands[0], 1, &operands[4], &operands[5]);") +;; See comment above `ashl3' about how this works. -(define_insn "*rotlsi3_1_one_bit_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ROTATE, DImode, operands)" - "rol{q}\t%0" - [(set_attr "type" "rotate") - (set_attr "length_immediate" "0") - (set_attr "mode" "DI")]) +(define_expand "3" + [(set (match_operand:SDWIM 0 "" "") + (any_shiftrt:SDWIM (match_operand:SDWIM 1 "" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "ix86_expand_binary_operator (, mode, operands); DONE;") -(define_insn "*rotldi3_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") - (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "e,c"))) +(define_insn_and_split "*3_doubleword" + [(set (match_operand:DWI 0 "register_operand" "=r") + (any_shiftrt:DWI (match_operand:DWI 1 "register_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "c"))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (ROTATE, DImode, operands)" - "@ - rol{q}\t{%2, %0|%0, %2} - rol{q}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "rotate") - (set_attr "mode" "DI")]) - -(define_expand "rotlsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] "" - "ix86_expand_binary_operator (ROTATE, SImode, operands); DONE;") + "#" + "(optimize && flag_peephole2) ? epilogue_completed : reload_completed" + [(const_int 0)] + "ix86_split_ (operands, NULL_RTX, mode); DONE;" + [(set_attr "type" "multi")]) + +;; By default we don't ask for a scratch register, because when DWImode +;; values are manipulated, registers are already at a premium. But if +;; we have one handy, we won't turn it away. + +(define_peephole2 + [(match_scratch:DWIH 3 "r") + (parallel [(set (match_operand: 0 "register_operand" "") + (any_shiftrt: + (match_operand: 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" ""))) + (clobber (reg:CC FLAGS_REG))]) + (match_dup 3)] + "TARGET_CMOVE" + [(const_int 0)] + "ix86_split_ (operands, operands[3], mode); DONE;") -(define_insn "*rotlsi3_1_one_bit" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) +(define_insn "x86_64_shrd" + [(set (match_operand:DI 0 "nonimmediate_operand" "+r*m") + (ior:DI (ashiftrt:DI (match_dup 0) + (match_operand:QI 2 "nonmemory_operand" "Jc")) + (ashift:DI (match_operand:DI 1 "register_operand" "r") + (minus:QI (const_int 64) (match_dup 2))))) (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ROTATE, SImode, operands)" - "rol{l}\t%0" - [(set_attr "type" "rotate") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) + "TARGET_64BIT" + "shrd{q}\t{%s2%1, %0|%0, %1, %2}" + [(set_attr "type" "ishift") + (set_attr "prefix_0f" "1") + (set_attr "mode" "DI") + (set_attr "athlon_decode" "vector") + (set_attr "amdfam10_decode" "vector")]) -(define_insn "*rotlsi3_1_one_bit_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (rotate:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const1_operand" "")))) +(define_insn "x86_shrd" + [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m") + (ior:SI (ashiftrt:SI (match_dup 0) + (match_operand:QI 2 "nonmemory_operand" "Ic")) + (ashift:SI (match_operand:SI 1 "register_operand" "r") + (minus:QI (const_int 32) (match_dup 2))))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ROTATE, SImode, operands)" - "rol{l}\t%k0" - [(set_attr "type" "rotate") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) + "" + "shrd{l}\t{%s2%1, %0|%0, %1, %2}" + [(set_attr "type" "ishift") + (set_attr "prefix_0f" "1") + (set_attr "mode" "SI") + (set_attr "pent_pair" "np") + (set_attr "athlon_decode" "vector") + (set_attr "amdfam10_decode" "vector")]) -(define_insn "*rotlsi3_1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") - (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) +(define_insn "ashrdi3_cvt" + [(set (match_operand:DI 0 "nonimmediate_operand" "=*d,rm") + (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "*a,0") + (match_operand:QI 2 "const_int_operand" ""))) (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (ROTATE, SImode, operands)" + "TARGET_64BIT && INTVAL (operands[2]) == 63 + && (TARGET_USE_CLTD || optimize_function_for_size_p (cfun)) + && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)" "@ - rol{l}\t{%2, %0|%0, %2} - rol{l}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "rotate") + {cqto|cqo} + sar{q}\t{%2, %0|%0, %2}" + [(set_attr "type" "imovx,ishift") + (set_attr "prefix_0f" "0,*") + (set_attr "length_immediate" "0,*") + (set_attr "modrm" "0,1") + (set_attr "mode" "DI")]) + +(define_insn "ashrsi3_cvt" + [(set (match_operand:SI 0 "nonimmediate_operand" "=*d,rm") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "*a,0") + (match_operand:QI 2 "const_int_operand" ""))) + (clobber (reg:CC FLAGS_REG))] + "INTVAL (operands[2]) == 31 + && (TARGET_USE_CLTD || optimize_function_for_size_p (cfun)) + && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" + "@ + {cltd|cdq} + sar{l}\t{%2, %0|%0, %2}" + [(set_attr "type" "imovx,ishift") + (set_attr "prefix_0f" "0,*") + (set_attr "length_immediate" "0,*") + (set_attr "modrm" "0,1") (set_attr "mode" "SI")]) -(define_insn "*rotlsi3_1_zext" - [(set (match_operand:DI 0 "register_operand" "=r,r") +(define_insn "*ashrsi3_cvt_zext" + [(set (match_operand:DI 0 "register_operand" "=*d,r") (zero_extend:DI - (rotate:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c")))) + (ashiftrt:SI (match_operand:SI 1 "register_operand" "*a,0") + (match_operand:QI 2 "const_int_operand" "")))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (ROTATE, SImode, operands)" + "TARGET_64BIT && INTVAL (operands[2]) == 31 + && (TARGET_USE_CLTD || optimize_function_for_size_p (cfun)) + && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)" "@ - rol{l}\t{%2, %k0|%k0, %2} - rol{l}\t{%b2, %k0|%k0, %b2}" - [(set_attr "type" "rotate") + {cltd|cdq} + sar{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "imovx,ishift") + (set_attr "prefix_0f" "0,*") + (set_attr "length_immediate" "0,*") + (set_attr "modrm" "0,1") (set_attr "mode" "SI")]) -(define_expand "rotlhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_binary_operator (ROTATE, HImode, operands); DONE;") +(define_expand "x86_shift_adj_3" + [(use (match_operand:SWI48 0 "register_operand" "")) + (use (match_operand:SWI48 1 "register_operand" "")) + (use (match_operand:QI 2 "register_operand" ""))] + "" +{ + rtx label = gen_label_rtx (); + rtx tmp; -(define_insn "*rotlhi3_1_one_bit" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ROTATE, HImode, operands)" - "rol{w}\t%0" - [(set_attr "type" "rotate") - (set_attr "length_immediate" "0") - (set_attr "mode" "HI")]) + emit_insn (gen_testqi_ccz_1 (operands[2], + GEN_INT (GET_MODE_BITSIZE (mode)))); -(define_insn "*rotlhi3_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") - (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (ROTATE, HImode, operands)" - "@ - rol{w}\t{%2, %0|%0, %2} - rol{w}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "rotate") - (set_attr "mode" "HI")]) + tmp = gen_rtx_REG (CCZmode, FLAGS_REG); + tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); + tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp, + gen_rtx_LABEL_REF (VOIDmode, label), + pc_rtx); + tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp)); + JUMP_LABEL (tmp) = label; -(define_split - [(set (match_operand:HI 0 "register_operand" "") - (rotate:HI (match_dup 0) (const_int 8))) - (clobber (reg:CC FLAGS_REG))] - "reload_completed" - [(parallel [(set (strict_low_part (match_dup 0)) - (bswap:HI (match_dup 0))) - (clobber (reg:CC FLAGS_REG))])] - "") + emit_move_insn (operands[0], operands[1]); + emit_insn (gen_ashr3_cvt (operands[1], operands[1], + GEN_INT (GET_MODE_BITSIZE (mode)-1))); + emit_label (label); + LABEL_NUSES (label) = 1; -(define_expand "rotlqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_binary_operator (ROTATE, QImode, operands); DONE;") + DONE; +}) + +(define_insn "*3_1" + [(set (match_operand:SWI 0 "nonimmediate_operand" "=m") + (any_shiftrt:SWI (match_operand:SWI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "c"))) + (clobber (reg:CC FLAGS_REG))] + "ix86_binary_operator_ok (, mode, operands)" +{ + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "{}\t%0"; + else + return "{}\t{%2, %0|%0, %2}"; +} + [(set_attr "type" "ishift") + (set (attr "length_immediate") + (if_then_else + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "")]) + +(define_insn "*si3_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (any_shiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "cI")))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT && ix86_binary_operator_ok (, SImode, operands)" +{ + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "{l}\t%k0"; + else + return "{l}\t{%2, %k0|%k0, %2}"; +} + [(set_attr "type" "ishift") + (set (attr "length_immediate") + (if_then_else + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "SI")]) -(define_insn "*rotlqi3_1_one_bit_slp" +(define_insn "*qi3_1_slp" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) - (rotate:QI (match_dup 0) - (match_operand:QI 1 "const1_operand" ""))) + (any_shiftrt:QI (match_dup 0) + (match_operand:QI 1 "nonmemory_operand" "cI"))) (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))" - "rol{b}\t%0" - [(set_attr "type" "rotate1") - (set_attr "length_immediate" "0") + "(optimize_function_for_size_p (cfun) + || !TARGET_PARTIAL_REG_STALL + || (operands[1] == const1_rtx + && TARGET_SHIFT1))" +{ + if (operands[1] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "{b}\t%0"; + else + return "{b}\t{%1, %0|%0, %1}"; +} + [(set_attr "type" "ishift1") + (set (attr "length_immediate") + (if_then_else + (and (match_operand 1 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "0") + (const_string "*"))) (set_attr "mode" "QI")]) -(define_insn "*rotlqi3_1_one_bit" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ROTATE, QImode, operands)" - "rol{b}\t%0" - [(set_attr "type" "rotate") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) +;; This pattern can't accept a variable shift count, since shifts by +;; zero don't affect the flags. We assume that shifts by constant +;; zero are optimized away. +(define_insn "*3_cmp" + [(set (reg FLAGS_REG) + (compare + (any_shiftrt:SWI + (match_operand:SWI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "" "")) + (const_int 0))) + (set (match_operand:SWI 0 "nonimmediate_operand" "=m") + (any_shiftrt:SWI (match_dup 1) (match_dup 2)))] + "(optimize_function_for_size_p (cfun) + || !TARGET_PARTIAL_FLAG_REG_STALL + || (operands[2] == const1_rtx + && TARGET_SHIFT1)) + && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (, mode, operands)" +{ + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "{}\t%0"; + else + return "{}\t{%2, %0|%0, %2}"; +} + [(set_attr "type" "ishift") + (set (attr "length_immediate") + (if_then_else + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "")]) + +(define_insn "*si3_cmp_zext" + [(set (reg FLAGS_REG) + (compare + (any_shiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "const_1_to_31_operand" "I")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (any_shiftrt:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT + && (optimize_function_for_size_p (cfun) + || !TARGET_PARTIAL_FLAG_REG_STALL + || (operands[2] == const1_rtx + && TARGET_SHIFT1)) + && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (, SImode, operands)" +{ + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "{l}\t%k0"; + else + return "{l}\t{%2, %k0|%k0, %2}"; +} + [(set_attr "type" "ishift") + (set (attr "length_immediate") + (if_then_else + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "SI")]) + +(define_insn "*3_cconly" + [(set (reg FLAGS_REG) + (compare + (any_shiftrt:SWI + (match_operand:SWI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "" "")) + (const_int 0))) + (clobber (match_scratch:SWI 0 "="))] + "(optimize_function_for_size_p (cfun) + || !TARGET_PARTIAL_FLAG_REG_STALL + || (operands[2] == const1_rtx + && TARGET_SHIFT1)) + && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (, mode, operands)" +{ + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "{}\t%0"; + else + return "{}\t{%2, %0|%0, %2}"; +} + [(set_attr "type" "ishift") + (set (attr "length_immediate") + (if_then_else + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "")]) + +;; Rotate instructions -(define_insn "*rotlqi3_1_slp" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,qm")) - (rotate:QI (match_dup 0) - (match_operand:QI 1 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "@ - rol{b}\t{%1, %0|%0, %1} - rol{b}\t{%b1, %0|%0, %b1}" - [(set_attr "type" "rotate1") - (set_attr "mode" "QI")]) +(define_expand "ti3" + [(set (match_operand:TI 0 "register_operand" "") + (any_rotate:TI (match_operand:TI 1 "register_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "TARGET_64BIT" +{ + if (const_1_to_63_operand (operands[2], VOIDmode)) + emit_insn (gen_ix86_ti3_doubleword + (operands[0], operands[1], operands[2])); + else + FAIL; -(define_insn "*rotlqi3_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") - (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (ROTATE, QImode, operands)" - "@ - rol{b}\t{%2, %0|%0, %2} - rol{b}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "rotate") - (set_attr "mode" "QI")]) + DONE; +}) -(define_expand "rotrdi3" +(define_expand "di3" [(set (match_operand:DI 0 "shiftdi_operand" "") - (rotate:DI (match_operand:DI 1 "shiftdi_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] + (any_rotate:DI (match_operand:DI 1 "shiftdi_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] "" { if (TARGET_64BIT) - { - ix86_expand_binary_operator (ROTATERT, DImode, operands); - DONE; - } - if (!const_1_to_31_operand (operands[2], VOIDmode)) + ix86_expand_binary_operator (, DImode, operands); + else if (const_1_to_31_operand (operands[2], VOIDmode)) + emit_insn (gen_ix86_di3_doubleword + (operands[0], operands[1], operands[2])); + else FAIL; - emit_insn (gen_ix86_rotrdi3 (operands[0], operands[1], operands[2])); + DONE; }) -;; Implement rotation using two double-precision shift instructions -;; and a scratch register. -(define_insn_and_split "ix86_rotrdi3" - [(set (match_operand:DI 0 "register_operand" "=r") - (rotatert:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I"))) +(define_expand "3" + [(set (match_operand:SWIM124 0 "nonimmediate_operand" "") + (any_rotate:SWIM124 (match_operand:SWIM124 1 "nonimmediate_operand" "") + (match_operand:QI 2 "nonmemory_operand" "")))] + "" + "ix86_expand_binary_operator (, mode, operands); DONE;") + +;; Implement rotation using two double-precision +;; shift instructions and a scratch register. + +(define_insn_and_split "ix86_rotl3_doubleword" + [(set (match_operand: 0 "register_operand" "=r") + (rotate: (match_operand: 1 "register_operand" "0") + (match_operand:QI 2 "" ""))) (clobber (reg:CC FLAGS_REG)) - (clobber (match_scratch:SI 3 "=&r"))] - "!TARGET_64BIT" + (clobber (match_scratch:DWIH 3 "=&r"))] "" - "&& reload_completed" + "#" + "reload_completed" [(set (match_dup 3) (match_dup 4)) (parallel [(set (match_dup 4) - (ior:SI (ashiftrt:SI (match_dup 4) (match_dup 2)) - (ashift:SI (match_dup 5) - (minus:QI (const_int 32) (match_dup 2))))) + (ior:DWIH (ashift:DWIH (match_dup 4) (match_dup 2)) + (lshiftrt:DWIH (match_dup 5) + (minus:QI (match_dup 6) (match_dup 2))))) (clobber (reg:CC FLAGS_REG))]) (parallel [(set (match_dup 5) - (ior:SI (ashiftrt:SI (match_dup 5) (match_dup 2)) - (ashift:SI (match_dup 3) - (minus:QI (const_int 32) (match_dup 2))))) + (ior:DWIH (ashift:DWIH (match_dup 5) (match_dup 2)) + (lshiftrt:DWIH (match_dup 3) + (minus:QI (match_dup 6) (match_dup 2))))) (clobber (reg:CC FLAGS_REG))])] - "split_di (&operands[0], 1, &operands[4], &operands[5]);") +{ + operands[6] = GEN_INT (GET_MODE_BITSIZE (mode)); -(define_insn "*rotrdi3_1_one_bit_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") - (rotatert:DI (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ROTATERT, DImode, operands)" - "ror{q}\t%0" - [(set_attr "type" "rotate") - (set_attr "length_immediate" "0") - (set_attr "mode" "DI")]) + split_ (&operands[0], 1, &operands[4], &operands[5]); +}) -(define_insn "*rotrdi3_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") - (rotatert:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "J,c"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (ROTATERT, DImode, operands)" - "@ - ror{q}\t{%2, %0|%0, %2} - ror{q}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "rotate") - (set_attr "mode" "DI")]) +(define_insn_and_split "ix86_rotr3_doubleword" + [(set (match_operand: 0 "register_operand" "=r") + (rotatert: (match_operand: 1 "register_operand" "0") + (match_operand:QI 2 "" ""))) + (clobber (reg:CC FLAGS_REG)) + (clobber (match_scratch:DWIH 3 "=&r"))] + "" + "#" + "reload_completed" + [(set (match_dup 3) (match_dup 4)) + (parallel + [(set (match_dup 4) + (ior:DWIH (ashiftrt:DWIH (match_dup 4) (match_dup 2)) + (ashift:DWIH (match_dup 5) + (minus:QI (match_dup 6) (match_dup 2))))) + (clobber (reg:CC FLAGS_REG))]) + (parallel + [(set (match_dup 5) + (ior:DWIH (ashiftrt:DWIH (match_dup 5) (match_dup 2)) + (ashift:DWIH (match_dup 3) + (minus:QI (match_dup 6) (match_dup 2))))) + (clobber (reg:CC FLAGS_REG))])] +{ + operands[6] = GEN_INT (GET_MODE_BITSIZE (mode)); -(define_expand "rotrsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "" - "ix86_expand_binary_operator (ROTATERT, SImode, operands); DONE;") + split_ (&operands[0], 1, &operands[4], &operands[5]); +}) -(define_insn "*rotrsi3_1_one_bit" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") - (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) +(define_insn "*3_1" + [(set (match_operand:SWI 0 "nonimmediate_operand" "=m") + (any_rotate:SWI (match_operand:SWI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "c"))) (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ROTATERT, SImode, operands)" - "ror{l}\t%0" + "ix86_binary_operator_ok (, mode, operands)" +{ + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "{}\t%0"; + else + return "{}\t{%2, %0|%0, %2}"; +} [(set_attr "type" "rotate") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) + (set (attr "length_immediate") + (if_then_else + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "")]) -(define_insn "*rotrsi3_1_one_bit_zext" +(define_insn "*si3_1_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI - (rotatert:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const1_operand" "")))) + (any_rotate:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:QI 2 "nonmemory_operand" "cI")))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ROTATERT, SImode, operands)" - "ror{l}\t%k0" - [(set_attr "type" "rotate") - (set_attr "length_immediate" "0") - (set_attr "mode" "SI")]) - -(define_insn "*rotrsi3_1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") - (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (ROTATERT, SImode, operands)" - "@ - ror{l}\t{%2, %0|%0, %2} - ror{l}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "rotate") - (set_attr "mode" "SI")]) - -(define_insn "*rotrsi3_1_zext" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (zero_extend:DI - (rotatert:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (ROTATERT, SImode, operands)" - "@ - ror{l}\t{%2, %k0|%k0, %2} - ror{l}\t{%b2, %k0|%k0, %b2}" + "TARGET_64BIT && ix86_binary_operator_ok (, SImode, operands)" +{ + if (operands[2] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "{l}\t%k0"; + else + return "{l}\t{%2, %k0|%k0, %2}"; +} [(set_attr "type" "rotate") + (set (attr "length_immediate") + (if_then_else + (and (match_operand 2 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "0") + (const_string "*"))) (set_attr "mode" "SI")]) -(define_expand "rotrhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_binary_operator (ROTATERT, HImode, operands); DONE;") - -(define_insn "*rotrhi3_one_bit" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") - (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ROTATERT, HImode, operands)" - "ror{w}\t%0" - [(set_attr "type" "rotate") - (set_attr "length_immediate" "0") - (set_attr "mode" "HI")]) - -(define_insn "*rotrhi3_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") - (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) +(define_insn "*qi3_1_slp" + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) + (any_rotate:QI (match_dup 0) + (match_operand:QI 1 "nonmemory_operand" "cI"))) (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (ROTATERT, HImode, operands)" - "@ - ror{w}\t{%2, %0|%0, %2} - ror{w}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "rotate") - (set_attr "mode" "HI")]) + "(optimize_function_for_size_p (cfun) + || !TARGET_PARTIAL_REG_STALL + || (operands[1] == const1_rtx + && TARGET_SHIFT1))" +{ + if (operands[1] == const1_rtx + && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))) + return "{b}\t%0"; + else + return "{b}\t{%1, %0|%0, %1}"; +} + [(set_attr "type" "rotate1") + (set (attr "length_immediate") + (if_then_else + (and (match_operand 1 "const1_operand" "") + (ne (symbol_ref "TARGET_SHIFT1 || optimize_function_for_size_p (cfun)") + (const_int 0))) + (const_string "0") + (const_string "*"))) + (set_attr "mode" "QI")]) (define_split [(set (match_operand:HI 0 "register_operand" "") - (rotatert:HI (match_dup 0) (const_int 8))) + (any_rotate:HI (match_dup 0) (const_int 8))) (clobber (reg:CC FLAGS_REG))] - "reload_completed" + "reload_completed + && (TARGET_USE_XCHGB || optimize_function_for_size_p (cfun))" [(parallel [(set (strict_low_part (match_dup 0)) (bswap:HI (match_dup 0))) (clobber (reg:CC FLAGS_REG))])] "") - -(define_expand "rotrqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "nonmemory_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_binary_operator (ROTATERT, QImode, operands); DONE;") - -(define_insn "*rotrqi3_1_one_bit" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") - (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(TARGET_SHIFT1 || optimize_function_for_size_p (cfun)) - && ix86_binary_operator_ok (ROTATERT, QImode, operands)" - "ror{b}\t%0" - [(set_attr "type" "rotate") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) - -(define_insn "*rotrqi3_1_one_bit_slp" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) - (rotatert:QI (match_dup 0) - (match_operand:QI 1 "const1_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun))" - "ror{b}\t%0" - [(set_attr "type" "rotate1") - (set_attr "length_immediate" "0") - (set_attr "mode" "QI")]) - -(define_insn "*rotrqi3_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm") - (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (ROTATERT, QImode, operands)" - "@ - ror{b}\t{%2, %0|%0, %2} - ror{b}\t{%b2, %0|%0, %b2}" - [(set_attr "type" "rotate") - (set_attr "mode" "QI")]) - -(define_insn "*rotrqi3_1_slp" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,qm")) - (rotatert:QI (match_dup 0) - (match_operand:QI 1 "nonmemory_operand" "I,c"))) - (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "@ - ror{b}\t{%1, %0|%0, %1} - ror{b}\t{%b1, %0|%0, %b1}" - [(set_attr "type" "rotate1") - (set_attr "mode" "QI")]) ;; Bit set / bit test instructions @@ -13578,6 +10345,8 @@ (match_operand 3 "register_operand" ""))] "" { + rtx (*gen_mov_insv_1) (rtx, rtx); + /* Handle insertions to %ah et al. */ if (INTVAL (operands[1]) != 8 || INTVAL (operands[2]) != 8) FAIL; @@ -13587,11 +10356,10 @@ if (! ext_register_operand (operands[0], VOIDmode)) FAIL; - if (TARGET_64BIT) - emit_insn (gen_movdi_insv_1_rex64 (operands[0], operands[3])); - else - emit_insn (gen_movsi_insv_1 (operands[0], operands[3])); + gen_mov_insv_1 = (TARGET_64BIT + ? gen_movdi_insv_1 : gen_movsi_insv_1); + emit_insn (gen_mov_insv_1 (operands[0], operands[3])); DONE; }) @@ -13743,33 +10511,19 @@ DONE; }) -(define_insn "*btdi_rex64" - [(set (reg:CCC FLAGS_REG) - (compare:CCC - (zero_extract:DI - (match_operand:DI 0 "register_operand" "r") - (const_int 1) - (match_operand:DI 1 "nonmemory_operand" "rN")) - (const_int 0)))] - "TARGET_64BIT && (TARGET_USE_BT || optimize_function_for_size_p (cfun))" - "bt{q}\t{%1, %0|%0, %1}" - [(set_attr "type" "alu1") - (set_attr "prefix_0f" "1") - (set_attr "mode" "DI")]) - -(define_insn "*btsi" +(define_insn "*bt" [(set (reg:CCC FLAGS_REG) (compare:CCC - (zero_extract:SI - (match_operand:SI 0 "register_operand" "r") + (zero_extract:SWI48 + (match_operand:SWI48 0 "register_operand" "r") (const_int 1) - (match_operand:SI 1 "nonmemory_operand" "rN")) + (match_operand:SWI48 1 "nonmemory_operand" "rN")) (const_int 0)))] "TARGET_USE_BT || optimize_function_for_size_p (cfun)" - "bt{l}\t{%1, %0|%0, %1}" + "bt{}\t{%1, %0|%0, %1}" [(set_attr "type" "alu1") (set_attr "prefix_0f" "1") - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) ;; Store-flag instructions. @@ -13822,20 +10576,6 @@ operands[2] = gen_lowpart (QImode, operands[0]); }) -(define_insn_and_split "*setcc__2" - [(set (match_operand:SWI48 0 "register_operand" "=q") - (match_operator:SWI48 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]))] - "TARGET_PARTIAL_REG_STALL" - "#" - "&& reload_completed" - [(set (match_dup 0) (const_int 0)) - (set (strict_low_part (match_dup 2)) (match_dup 1))] -{ - PUT_MODE (operands[1], QImode); - operands[2] = gen_lowpart (QImode, operands[0]); -}) - (define_insn "*setcc_qi" [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") (match_operator:QI 1 "ix86_comparison_operator" @@ -14025,97 +10765,31 @@ "" [(set (pc) (if_then_else (match_dup 0) - (label_ref (match_dup 1)) - (pc)))] -{ - rtx new_op0 = copy_rtx (operands[0]); - operands[0] = new_op0; - PUT_MODE (new_op0, VOIDmode); - PUT_CODE (new_op0, ix86_reverse_condition (GET_CODE (new_op0), - GET_MODE (XEXP (new_op0, 0)))); - - /* Make sure that (a) the CCmode we have for the flags is strong - enough for the reversed compare or (b) we have a valid FP compare. */ - if (! ix86_comparison_operator (new_op0, VOIDmode)) - FAIL; -}) - -;; zero_extend in SImode is correct, since this is what combine pass -;; generates from shift insn with QImode operand. Actually, the mode of -;; operand 2 (bit offset operand) doesn't matter since bt insn takes -;; appropriate modulo of the bit offset value. - -(define_insn_and_split "*jcc_btdi_rex64" - [(set (pc) - (if_then_else (match_operator 0 "bt_comparison_operator" - [(zero_extract:DI - (match_operand:DI 1 "register_operand" "r") - (const_int 1) - (zero_extend:SI - (match_operand:QI 2 "register_operand" "r"))) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && (TARGET_USE_BT || optimize_function_for_size_p (cfun))" - "#" - "&& 1" - [(set (reg:CCC FLAGS_REG) - (compare:CCC - (zero_extract:DI - (match_dup 1) - (const_int 1) - (match_dup 2)) - (const_int 0))) - (set (pc) - (if_then_else (match_op_dup 0 [(reg:CCC FLAGS_REG) (const_int 0)]) - (label_ref (match_dup 3)) - (pc)))] -{ - operands[2] = simplify_gen_subreg (DImode, operands[2], QImode, 0); - - PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0]))); -}) - -;; avoid useless masking of bit offset operand -(define_insn_and_split "*jcc_btdi_mask_rex64" - [(set (pc) - (if_then_else (match_operator 0 "bt_comparison_operator" - [(zero_extract:DI - (match_operand:DI 1 "register_operand" "r") - (const_int 1) - (and:SI - (match_operand:SI 2 "register_operand" "r") - (match_operand:SI 3 "const_int_operand" "n")))]) - (label_ref (match_operand 4 "" "")) - (pc))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && (TARGET_USE_BT || optimize_function_for_size_p (cfun)) - && (INTVAL (operands[3]) & 0x3f) == 0x3f" - "#" - "&& 1" - [(set (reg:CCC FLAGS_REG) - (compare:CCC - (zero_extract:DI - (match_dup 1) - (const_int 1) - (match_dup 2)) - (const_int 0))) - (set (pc) - (if_then_else (match_op_dup 0 [(reg:CCC FLAGS_REG) (const_int 0)]) - (label_ref (match_dup 4)) + (label_ref (match_dup 1)) (pc)))] { - operands[2] = simplify_gen_subreg (DImode, operands[2], SImode, 0); + rtx new_op0 = copy_rtx (operands[0]); + operands[0] = new_op0; + PUT_MODE (new_op0, VOIDmode); + PUT_CODE (new_op0, ix86_reverse_condition (GET_CODE (new_op0), + GET_MODE (XEXP (new_op0, 0)))); - PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0]))); + /* Make sure that (a) the CCmode we have for the flags is strong + enough for the reversed compare or (b) we have a valid FP compare. */ + if (! ix86_comparison_operator (new_op0, VOIDmode)) + FAIL; }) -(define_insn_and_split "*jcc_btsi" +;; zero_extend in SImode is correct also for DImode, since this is what combine +;; pass generates from shift insn with QImode operand. Actually, the mode +;; of operand 2 (bit offset operand) doesn't matter since bt insn takes +;; appropriate modulo of the bit offset value. + +(define_insn_and_split "*jcc_bt" [(set (pc) (if_then_else (match_operator 0 "bt_comparison_operator" - [(zero_extract:SI - (match_operand:SI 1 "register_operand" "r") + [(zero_extract:SWI48 + (match_operand:SWI48 1 "register_operand" "r") (const_int 1) (zero_extend:SI (match_operand:QI 2 "register_operand" "r"))) @@ -14128,7 +10802,7 @@ "&& 1" [(set (reg:CCC FLAGS_REG) (compare:CCC - (zero_extract:SI + (zero_extract:SWI48 (match_dup 1) (const_int 1) (match_dup 2)) @@ -14138,17 +10812,18 @@ (label_ref (match_dup 3)) (pc)))] { - operands[2] = simplify_gen_subreg (SImode, operands[2], QImode, 0); + operands[2] = simplify_gen_subreg (mode, operands[2], QImode, 0); PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0]))); }) -;; avoid useless masking of bit offset operand -(define_insn_and_split "*jcc_btsi_mask" +;; Avoid useless masking of bit offset operand. "and" in SImode is correct +;; also for DImode, this is what combine produces. +(define_insn_and_split "*jcc_bt_mask" [(set (pc) (if_then_else (match_operator 0 "bt_comparison_operator" - [(zero_extract:SI - (match_operand:SI 1 "register_operand" "r") + [(zero_extract:SWI48 + (match_operand:SWI48 1 "register_operand" "r") (const_int 1) (and:SI (match_operand:SI 2 "register_operand" "r") @@ -14157,12 +10832,13 @@ (pc))) (clobber (reg:CC FLAGS_REG))] "(TARGET_USE_BT || optimize_function_for_size_p (cfun)) - && (INTVAL (operands[3]) & 0x1f) == 0x1f" + && (INTVAL (operands[3]) & (GET_MODE_BITSIZE (mode)-1)) + == GET_MODE_BITSIZE (mode)-1" "#" "&& 1" [(set (reg:CCC FLAGS_REG) (compare:CCC - (zero_extract:SI + (zero_extract:SWI48 (match_dup 1) (const_int 1) (match_dup 2)) @@ -14171,7 +10847,11 @@ (if_then_else (match_op_dup 0 [(reg:CCC FLAGS_REG) (const_int 0)]) (label_ref (match_dup 4)) (pc)))] - "PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0])));") +{ + operands[2] = simplify_gen_subreg (mode, operands[2], SImode, 0); + + PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0]))); +}) (define_insn_and_split "*jcc_btsi_1" [(set (pc) @@ -14242,7 +10922,7 @@ ;; Define combination compare-and-branch fp compare instructions to help ;; combine. -(define_insn "*fp_jcc_3_387" +(define_insn "*fp_jcc_1_387" [(set (pc) (if_then_else (match_operator 0 "ix86_fp_comparison_operator" [(match_operand 1 "register_operand" "f") @@ -14260,7 +10940,7 @@ && !TARGET_CMOVE" "#") -(define_insn "*fp_jcc_4_387" +(define_insn "*fp_jcc_1r_387" [(set (pc) (if_then_else (match_operator 0 "ix86_fp_comparison_operator" [(match_operand 1 "register_operand" "f") @@ -14278,7 +10958,7 @@ && !TARGET_CMOVE" "#") -(define_insn "*fp_jcc_5_387" +(define_insn "*fp_jcc_2_387" [(set (pc) (if_then_else (match_operator 0 "ix86_fp_comparison_operator" [(match_operand 1 "register_operand" "f") @@ -14293,7 +10973,7 @@ && !TARGET_CMOVE" "#") -(define_insn "*fp_jcc_6_387" +(define_insn "*fp_jcc_2r_387" [(set (pc) (if_then_else (match_operator 0 "ix86_fp_comparison_operator" [(match_operand 1 "register_operand" "f") @@ -14308,7 +10988,7 @@ && !TARGET_CMOVE" "#") -(define_insn "*fp_jcc_7_387" +(define_insn "*fp_jcc_3_387" [(set (pc) (if_then_else (match_operator 0 "ix86_fp_comparison_operator" [(match_operand 1 "register_operand" "f") @@ -14325,29 +11005,6 @@ && !TARGET_CMOVE" "#") -;; The order of operands in *fp_jcc_8_387 is forced by combine in -;; simplify_comparison () function. Float operator is treated as RTX_OBJ -;; with a precedence over other operators and is always put in the first -;; place. Swap condition and operands to match ficom instruction. - -(define_insn "*fp_jcc_8_387" - [(set (pc) - (if_then_else (match_operator 0 "ix86_fp_comparison_operator" - [(match_operator 1 "float_operator" - [(match_operand:X87MODEI12 2 "nonimmediate_operand" "m,?r")]) - (match_operand 3 "register_operand" "f,f")]) - (label_ref (match_operand 4 "" "")) - (pc))) - (clobber (reg:CCFP FPSR_REG)) - (clobber (reg:CCFP FLAGS_REG)) - (clobber (match_scratch:HI 5 "=a,a"))] - "X87_FLOAT_MODE_P (GET_MODE (operands[3])) - && (TARGET_USE_MODE_FIOP || optimize_function_for_size_p (cfun)) - && GET_MODE (operands[1]) == GET_MODE (operands[3]) - && ix86_fp_compare_mode (swap_condition (GET_CODE (operands[0]))) == CCFPmode - && !TARGET_CMOVE" - "#") - (define_split [(set (pc) (if_then_else (match_operator 0 "ix86_fp_comparison_operator" @@ -14383,12 +11040,37 @@ DONE; }) +;; The order of operands in *fp_jcc_4_387 is forced by combine in +;; simplify_comparison () function. Float operator is treated as RTX_OBJ +;; with a precedence over other operators and is always put in the first +;; place. Swap condition and operands to match ficom instruction. + +(define_insn "*fp_jcc_4__387" + [(set (pc) + (if_then_else + (match_operator 0 "ix86_swapped_fp_comparison_operator" + [(match_operator 1 "float_operator" + [(match_operand:X87MODEI12 2 "nonimmediate_operand" "m,?r")]) + (match_operand 3 "register_operand" "f,f")]) + (label_ref (match_operand 4 "" "")) + (pc))) + (clobber (reg:CCFP FPSR_REG)) + (clobber (reg:CCFP FLAGS_REG)) + (clobber (match_scratch:HI 5 "=a,a"))] + "X87_FLOAT_MODE_P (GET_MODE (operands[3])) + && (TARGET_USE_MODE_FIOP || optimize_function_for_size_p (cfun)) + && GET_MODE (operands[1]) == GET_MODE (operands[3]) + && ix86_fp_compare_mode (swap_condition (GET_CODE (operands[0]))) == CCFPmode + && !TARGET_CMOVE" + "#") + (define_split [(set (pc) - (if_then_else (match_operator 0 "ix86_fp_comparison_operator" - [(match_operator 1 "float_operator" - [(match_operand:X87MODEI12 2 "memory_operand" "")]) - (match_operand 3 "register_operand" "")]) + (if_then_else + (match_operator 0 "ix86_swapped_fp_comparison_operator" + [(match_operator 1 "float_operator" + [(match_operand:X87MODEI12 2 "memory_operand" "")]) + (match_operand 3 "register_operand" "")]) (match_operand 4 "" "") (match_operand 5 "" ""))) (clobber (reg:CCFP FPSR_REG)) @@ -14398,6 +11080,7 @@ [(const_int 0)] { operands[7] = gen_rtx_FLOAT (GET_MODE (operands[1]), operands[2]); + ix86_split_fp_branch (swap_condition (GET_CODE (operands[0])), operands[3], operands[7], operands[4], operands[5], operands[6], NULL_RTX); @@ -14407,10 +11090,11 @@ ;; %%% Kill this when reload knows how to do it. (define_split [(set (pc) - (if_then_else (match_operator 0 "ix86_fp_comparison_operator" - [(match_operator 1 "float_operator" - [(match_operand:X87MODEI12 2 "register_operand" "")]) - (match_operand 3 "register_operand" "")]) + (if_then_else + (match_operator 0 "ix86_swapped_fp_comparison_operator" + [(match_operator 1 "float_operator" + [(match_operand:X87MODEI12 2 "register_operand" "")]) + (match_operand 3 "register_operand" "")]) (match_operand 4 "" "") (match_operand 5 "" ""))) (clobber (reg:CCFP FPSR_REG)) @@ -14421,6 +11105,7 @@ { operands[7] = ix86_force_to_memory (GET_MODE (operands[2]), operands[2]); operands[7] = gen_rtx_FLOAT (GET_MODE (operands[1]), operands[7]); + ix86_split_fp_branch (swap_condition (GET_CODE (operands[0])), operands[3], operands[7], operands[4], operands[5], operands[6], operands[2]); @@ -14551,6 +11236,10 @@ ;; checked for calls. This is a bug in the generic code, but it isn't that ;; easy to fix. Ignore it for now and be prepared to fix things up. +;; P6 processors will jump to the address after the decrement when %esp +;; is used as a call operand, so they will execute return address as a code. +;; See Pentium Pro errata 70, Pentium 2 errata A33 and Pentium 3 errata E17. + ;; Call subroutine returning no value. (define_expand "call_pop" @@ -14561,15 +11250,17 @@ (match_operand:SI 3 "" "")))])] "!TARGET_64BIT" { - ix86_expand_call (NULL, operands[0], operands[1], operands[2], operands[3], 0); + ix86_expand_call (NULL, operands[0], operands[1], + operands[2], operands[3], 0); DONE; }) (define_insn "*call_pop_0" [(call (mem:QI (match_operand:SI 0 "constant_call_address_operand" "")) (match_operand:SI 1 "" "")) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) - (match_operand:SI 2 "immediate_operand" "")))] + (set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI 2 "immediate_operand" "")))] "!TARGET_64BIT" { if (SIBLING_CALL_P (insn)) @@ -14580,11 +11271,12 @@ [(set_attr "type" "call")]) (define_insn "*call_pop_1" - [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "rsm")) + [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lsm")) (match_operand:SI 1 "" "")) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) - (match_operand:SI 2 "immediate_operand" "i")))] - "!SIBLING_CALL_P (insn) && !TARGET_64BIT" + (set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI 2 "immediate_operand" "i")))] + "!TARGET_64BIT && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[0], Pmode)) return "call\t%P0"; @@ -14595,9 +11287,10 @@ (define_insn "*sibcall_pop_1" [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,U")) (match_operand:SI 1 "" "")) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) - (match_operand:SI 2 "immediate_operand" "i,i")))] - "SIBLING_CALL_P (insn) && !TARGET_64BIT" + (set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI 2 "immediate_operand" "i,i")))] + "!TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P0 jmp\t%A0" @@ -14636,9 +11329,9 @@ [(set_attr "type" "call")]) (define_insn "*call_1" - [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "rsm")) + [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lsm")) (match_operand 1 "" ""))] - "!SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[0], Pmode)) return "call\t%P0"; @@ -14649,7 +11342,7 @@ (define_insn "*sibcall_1" [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,U")) (match_operand 1 "" ""))] - "SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P0 jmp\t%A0" @@ -14658,7 +11351,7 @@ (define_insn "*call_1_rex64" [(call (mem:QI (match_operand:DI 0 "call_insn_operand" "rsm")) (match_operand 1 "" ""))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT + "TARGET_64BIT && !SIBLING_CALL_P (insn) && ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC" { if (constant_call_address_operand (operands[0], Pmode)) @@ -14683,7 +11376,7 @@ (clobber (reg:TI XMM15_REG)) (clobber (reg:DI SI_REG)) (clobber (reg:DI DI_REG))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[0], Pmode)) return "call\t%P0"; @@ -14694,14 +11387,14 @@ (define_insn "*call_1_rex64_large" [(call (mem:QI (match_operand:DI 0 "call_insn_operand" "rm")) (match_operand 1 "" ""))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && !SIBLING_CALL_P (insn)" "call\t%A0" [(set_attr "type" "call")]) (define_insn "*sibcall_1_rex64" [(call (mem:QI (match_operand:DI 0 "sibcall_insn_operand" "s,U")) (match_operand 1 "" ""))] - "SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P0 jmp\t%A0" @@ -14727,10 +11420,11 @@ (call (match_operand:QI 1 "" "") (match_operand:SI 2 "" ""))) (use (match_operand:SI 3 "" ""))] - ;; Operand 2 not used on the i386. + ;; Operand 3 is not used on the i386. "" { - ix86_expand_call (operands[0], operands[1], operands[2], operands[3], NULL, 0); + ix86_expand_call (operands[0], operands[1], operands[2], + operands[3], NULL, 0); DONE; }) @@ -14739,10 +11433,11 @@ (call (match_operand:QI 1 "" "") (match_operand:SI 2 "" ""))) (use (match_operand:SI 3 "" ""))] - ;; Operand 2 not used on the i386. + ;; Operand 3 is not used on the i386. "" { - ix86_expand_call (operands[0], operands[1], operands[2], operands[3], NULL, 1); + ix86_expand_call (operands[0], operands[1], operands[2], + operands[3], NULL, 1); DONE; }) @@ -14893,6 +11588,16 @@ (set_attr "length_immediate" "0") (set_attr "modrm" "0")]) +(define_insn "vswapmov" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "register_operand" "r")) + (unspec_volatile [(const_int 0)] UNSPECV_VSWAPMOV)] + "" + "movl.s\t{%1, %0|%0, %1}" + [(set_attr "length" "2") + (set_attr "length_immediate" "0") + (set_attr "modrm" "0")]) + ;; Pad to 16-byte boundary, max skip in op0. Used to avoid ;; branch prediction penalty for the third jump in a 16-byte ;; block on K8. @@ -15020,38 +11725,33 @@ "leave" [(set_attr "type" "leave")]) -(define_expand "ffssi2" - [(parallel - [(set (match_operand:SI 0 "register_operand" "") - (ffs:SI (match_operand:SI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:SI 2 "")) - (clobber (reg:CC FLAGS_REG))])] - "" -{ - if (TARGET_CMOVE) - { - emit_insn (gen_ffs_cmove (operands[0], operands[1])); - DONE; - } -}) +;; Bit manipulation instructions. -(define_expand "ffs_cmove" +(define_expand "ffs2" [(set (match_dup 2) (const_int -1)) (parallel [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (match_operand:SI 1 "nonimmediate_operand" "") - (const_int 0))) - (set (match_operand:SI 0 "register_operand" "") - (ctz:SI (match_dup 1)))]) - (set (match_dup 0) (if_then_else:SI + (compare:CCZ + (match_operand:SWI48 1 "nonimmediate_operand" "") + (const_int 0))) + (set (match_operand:SWI48 0 "register_operand" "") + (ctz:SWI48 (match_dup 1)))]) + (set (match_dup 0) (if_then_else:SWI48 (eq (reg:CCZ FLAGS_REG) (const_int 0)) (match_dup 2) (match_dup 0))) - (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 1))) + (parallel [(set (match_dup 0) (plus:SWI48 (match_dup 0) (const_int 1))) (clobber (reg:CC FLAGS_REG))])] - "TARGET_CMOVE" - "operands[2] = gen_reg_rtx (SImode);") + "" +{ + if (mode == SImode && !TARGET_CMOVE) + { + emit_insn (gen_ffssi2_no_cmove (operands[0], operands [1])); + DONE; + } + operands[2] = gen_reg_rtx (mode); +}) -(define_insn_and_split "*ffs_no_cmove" +(define_insn_and_split "ffssi2_no_cmove" [(set (match_operand:SI 0 "register_operand" "=r") (ffs:SI (match_operand:SI 1 "nonimmediate_operand" "rm"))) (clobber (match_scratch:SI 2 "=&q")) @@ -15075,93 +11775,68 @@ ix86_expand_clear (operands[2]); }) -(define_insn "*ffssi_1" +(define_insn "*ffs_1" [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (match_operand:SI 1 "nonimmediate_operand" "rm") + (compare:CCZ (match_operand:SWI48 1 "nonimmediate_operand" "rm") (const_int 0))) - (set (match_operand:SI 0 "register_operand" "=r") - (ctz:SI (match_dup 1)))] + (set (match_operand:SWI48 0 "register_operand" "=r") + (ctz:SWI48 (match_dup 1)))] "" - "bsf{l}\t{%1, %0|%0, %1}" - [(set_attr "type" "alu1") - (set_attr "prefix_0f" "1") - (set_attr "mode" "SI")]) - -(define_expand "ffsdi2" - [(set (match_dup 2) (const_int -1)) - (parallel [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (match_operand:DI 1 "nonimmediate_operand" "") - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "") - (ctz:DI (match_dup 1)))]) - (set (match_dup 0) (if_then_else:DI - (eq (reg:CCZ FLAGS_REG) (const_int 0)) - (match_dup 2) - (match_dup 0))) - (parallel [(set (match_dup 0) (plus:DI (match_dup 0) (const_int 1))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" - "operands[2] = gen_reg_rtx (DImode);") - -(define_insn "*ffsdi_1" - [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (match_operand:DI 1 "nonimmediate_operand" "rm") - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (ctz:DI (match_dup 1)))] - "TARGET_64BIT" - "bsf{q}\t{%1, %0|%0, %1}" + "bsf{}\t{%1, %0|%0, %1}" [(set_attr "type" "alu1") (set_attr "prefix_0f" "1") - (set_attr "mode" "DI")]) + (set_attr "mode" "")]) -(define_insn "ctzsi2" - [(set (match_operand:SI 0 "register_operand" "=r") - (ctz:SI (match_operand:SI 1 "nonimmediate_operand" "rm"))) +(define_insn "ctz2" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (ctz:SWI48 (match_operand:SWI48 1 "nonimmediate_operand" "rm"))) (clobber (reg:CC FLAGS_REG))] "" - "bsf{l}\t{%1, %0|%0, %1}" - [(set_attr "type" "alu1") - (set_attr "prefix_0f" "1") - (set_attr "mode" "SI")]) - -(define_insn "ctzdi2" - [(set (match_operand:DI 0 "register_operand" "=r") - (ctz:DI (match_operand:DI 1 "nonimmediate_operand" "rm"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "bsf{q}\t{%1, %0|%0, %1}" + "bsf{}\t{%1, %0|%0, %1}" [(set_attr "type" "alu1") (set_attr "prefix_0f" "1") - (set_attr "mode" "DI")]) + (set_attr "mode" "")]) -(define_expand "clzsi2" +(define_expand "clz2" [(parallel - [(set (match_operand:SI 0 "register_operand" "") - (minus:SI (const_int 31) - (clz:SI (match_operand:SI 1 "nonimmediate_operand" "")))) + [(set (match_operand:SWI248 0 "register_operand" "") + (minus:SWI248 + (match_dup 2) + (clz:SWI248 (match_operand:SWI248 1 "nonimmediate_operand" "")))) (clobber (reg:CC FLAGS_REG))]) (parallel - [(set (match_dup 0) (xor:SI (match_dup 0) (const_int 31))) + [(set (match_dup 0) (xor:SWI248 (match_dup 0) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] "" { if (TARGET_ABM) { - emit_insn (gen_clzsi2_abm (operands[0], operands[1])); + emit_insn (gen_clz2_abm (operands[0], operands[1])); DONE; } + operands[2] = GEN_INT (GET_MODE_BITSIZE (mode)-1); }) -(define_insn "clzsi2_abm" - [(set (match_operand:SI 0 "register_operand" "=r") - (clz:SI (match_operand:SI 1 "nonimmediate_operand" "rm"))) +(define_insn "clz2_abm" + [(set (match_operand:SWI248 0 "register_operand" "=r") + (clz:SWI248 (match_operand:SWI248 1 "nonimmediate_operand" "rm"))) (clobber (reg:CC FLAGS_REG))] "TARGET_ABM" - "lzcnt{l}\t{%1, %0|%0, %1}" + "lzcnt{}\t{%1, %0|%0, %1}" [(set_attr "prefix_rep" "1") (set_attr "type" "bitmanip") - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) + +(define_insn "bsr_rex64" + [(set (match_operand:DI 0 "register_operand" "=r") + (minus:DI (const_int 63) + (clz:DI (match_operand:DI 1 "nonimmediate_operand" "rm")))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT" + "bsr{q}\t{%1, %0|%0, %1}" + [(set_attr "type" "alu1") + (set_attr "prefix_0f" "1") + (set_attr "mode" "DI")]) (define_insn "bsr" [(set (match_operand:SI 0 "register_operand" "=r") @@ -15174,6 +11849,17 @@ (set_attr "prefix_0f" "1") (set_attr "mode" "SI")]) +(define_insn "*bsrhi" + [(set (match_operand:HI 0 "register_operand" "=r") + (minus:HI (const_int 15) + (clz:HI (match_operand:HI 1 "nonimmediate_operand" "rm")))) + (clobber (reg:CC FLAGS_REG))] + "" + "bsr{w}\t{%1, %0|%0, %1}" + [(set_attr "type" "alu1") + (set_attr "prefix_0f" "1") + (set_attr "mode" "HI")]) + (define_insn "popcount2" [(set (match_operand:SWI248 0 "register_operand" "=r") (popcount:SWI248 @@ -15223,19 +11909,19 @@ #if TARGET_MACHO return "popcnt\t{%1, %0|%0, %1}"; #else - return "popcnt{}\t{%1, %0|%0, %1}"; + return "popcnt{l}\t{%1, %0|%0, %1}"; #endif } [(set_attr "prefix_rep" "1") (set_attr "type" "bitmanip") (set_attr "mode" "SI")]) -(define_expand "bswapsi2" - [(set (match_operand:SI 0 "register_operand" "") - (bswap:SI (match_operand:SI 1 "register_operand" "")))] +(define_expand "bswap2" + [(set (match_operand:SWI48 0 "register_operand" "") + (bswap:SWI48 (match_operand:SWI48 1 "register_operand" "")))] "" { - if (!(TARGET_BSWAP || TARGET_MOVBE)) + if (mode == SImode && !(TARGET_BSWAP || TARGET_MOVBE)) { rtx x = operands[0]; @@ -15247,28 +11933,29 @@ } }) -(define_insn "*bswapsi_movbe" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m") - (bswap:SI (match_operand:SI 1 "nonimmediate_operand" "0,m,r")))] - "TARGET_MOVBE && !(MEM_P (operands[0]) && MEM_P (operands[1]))" +(define_insn "*bswap2_movbe" + [(set (match_operand:SWI48 0 "nonimmediate_operand" "=r,r,m") + (bswap:SWI48 (match_operand:SWI48 1 "nonimmediate_operand" "0,m,r")))] + "TARGET_MOVBE + && !(MEM_P (operands[0]) && MEM_P (operands[1]))" "@ bswap\t%0 movbe\t{%1, %0|%0, %1} movbe\t{%1, %0|%0, %1}" - [(set_attr "type" "*,imov,imov") - (set_attr "modrm" "*,1,1") - (set_attr "prefix_0f" "1") + [(set_attr "type" "bitmanip,imov,imov") + (set_attr "modrm" "0,1,1") + (set_attr "prefix_0f" "*,1,1") (set_attr "prefix_extra" "*,1,1") - (set_attr "length" "2,*,*") - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) -(define_insn "*bswapsi_1" - [(set (match_operand:SI 0 "register_operand" "=r") - (bswap:SI (match_operand:SI 1 "register_operand" "0")))] +(define_insn "*bswap2_1" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (bswap:SWI48 (match_operand:SWI48 1 "register_operand" "0")))] "TARGET_BSWAP" "bswap\t%0" - [(set_attr "prefix_0f" "1") - (set_attr "length" "2")]) + [(set_attr "type" "bitmanip") + (set_attr "modrm" "0") + (set_attr "mode" "")]) (define_insn "*bswaphi_lowpart_1" [(set (strict_low_part (match_operand:HI 0 "register_operand" "+Q,r")) @@ -15290,114 +11977,6 @@ [(set_attr "length" "4") (set_attr "mode" "HI")]) -(define_expand "bswapdi2" - [(set (match_operand:DI 0 "register_operand" "") - (bswap:DI (match_operand:DI 1 "register_operand" "")))] - "TARGET_64BIT" - "") - -(define_insn "*bswapdi_movbe" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m") - (bswap:DI (match_operand:DI 1 "nonimmediate_operand" "0,m,r")))] - "TARGET_64BIT && TARGET_MOVBE - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" - "@ - bswap\t%0 - movbe\t{%1, %0|%0, %1} - movbe\t{%1, %0|%0, %1}" - [(set_attr "type" "*,imov,imov") - (set_attr "modrm" "*,1,1") - (set_attr "prefix_0f" "1") - (set_attr "prefix_extra" "*,1,1") - (set_attr "length" "3,*,*") - (set_attr "mode" "DI")]) - -(define_insn "*bswapdi_1" - [(set (match_operand:DI 0 "register_operand" "=r") - (bswap:DI (match_operand:DI 1 "register_operand" "0")))] - "TARGET_64BIT" - "bswap\t%0" - [(set_attr "prefix_0f" "1") - (set_attr "length" "3")]) - -(define_expand "clzdi2" - [(parallel - [(set (match_operand:DI 0 "register_operand" "") - (minus:DI (const_int 63) - (clz:DI (match_operand:DI 1 "nonimmediate_operand" "")))) - (clobber (reg:CC FLAGS_REG))]) - (parallel - [(set (match_dup 0) (xor:DI (match_dup 0) (const_int 63))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" -{ - if (TARGET_ABM) - { - emit_insn (gen_clzdi2_abm (operands[0], operands[1])); - DONE; - } -}) - -(define_insn "clzdi2_abm" - [(set (match_operand:DI 0 "register_operand" "=r") - (clz:DI (match_operand:DI 1 "nonimmediate_operand" "rm"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && TARGET_ABM" - "lzcnt{q}\t{%1, %0|%0, %1}" - [(set_attr "prefix_rep" "1") - (set_attr "type" "bitmanip") - (set_attr "mode" "DI")]) - -(define_insn "bsr_rex64" - [(set (match_operand:DI 0 "register_operand" "=r") - (minus:DI (const_int 63) - (clz:DI (match_operand:DI 1 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "bsr{q}\t{%1, %0|%0, %1}" - [(set_attr "type" "alu1") - (set_attr "prefix_0f" "1") - (set_attr "mode" "DI")]) - -(define_expand "clzhi2" - [(parallel - [(set (match_operand:HI 0 "register_operand" "") - (minus:HI (const_int 15) - (clz:HI (match_operand:HI 1 "nonimmediate_operand" "")))) - (clobber (reg:CC FLAGS_REG))]) - (parallel - [(set (match_dup 0) (xor:HI (match_dup 0) (const_int 15))) - (clobber (reg:CC FLAGS_REG))])] - "" -{ - if (TARGET_ABM) - { - emit_insn (gen_clzhi2_abm (operands[0], operands[1])); - DONE; - } -}) - -(define_insn "clzhi2_abm" - [(set (match_operand:HI 0 "register_operand" "=r") - (clz:HI (match_operand:HI 1 "nonimmediate_operand" "rm"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_ABM" - "lzcnt{w}\t{%1, %0|%0, %1}" - [(set_attr "prefix_rep" "1") - (set_attr "type" "bitmanip") - (set_attr "mode" "HI")]) - -(define_insn "*bsrhi" - [(set (match_operand:HI 0 "register_operand" "=r") - (minus:HI (const_int 15) - (clz:HI (match_operand:HI 1 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] - "" - "bsr{w}\t{%1, %0|%0, %1}" - [(set_attr "type" "alu1") - (set_attr "prefix_0f" "1") - (set_attr "mode" "HI")]) - (define_expand "paritydi2" [(set (match_operand:DI 0 "register_operand" "") (parity:DI (match_operand:DI 1 "register_operand" "")))] @@ -15420,15 +11999,35 @@ { rtx tmp = gen_reg_rtx (SImode); - emit_insn (gen_zero_extendqisi2 (tmp, scratch)); - emit_insn (gen_zero_extendsidi2 (operands[0], tmp)); - } + emit_insn (gen_zero_extendqisi2 (tmp, scratch)); + emit_insn (gen_zero_extendsidi2 (operands[0], tmp)); + } + DONE; +}) + +(define_expand "paritysi2" + [(set (match_operand:SI 0 "register_operand" "") + (parity:SI (match_operand:SI 1 "register_operand" "")))] + "! TARGET_POPCNT" +{ + rtx scratch = gen_reg_rtx (QImode); + rtx cond; + + emit_insn (gen_paritysi2_cmp (NULL_RTX, NULL_RTX, operands[1])); + + cond = gen_rtx_fmt_ee (ORDERED, QImode, + gen_rtx_REG (CCmode, FLAGS_REG), + const0_rtx); + emit_insn (gen_rtx_SET (VOIDmode, scratch, cond)); + + emit_insn (gen_zero_extendqisi2 (operands[0], scratch)); DONE; }) (define_insn_and_split "paritydi2_cmp" [(set (reg:CC FLAGS_REG) - (parity:CC (match_operand:DI 3 "register_operand" "0"))) + (unspec:CC [(match_operand:DI 3 "register_operand" "0")] + UNSPEC_PARITY)) (clobber (match_scratch:DI 0 "=r")) (clobber (match_scratch:SI 1 "=&r")) (clobber (match_scratch:HI 2 "=Q"))] @@ -15441,7 +12040,7 @@ (clobber (reg:CC FLAGS_REG))]) (parallel [(set (reg:CC FLAGS_REG) - (parity:CC (match_dup 1))) + (unspec:CC [(match_dup 1)] UNSPEC_PARITY)) (clobber (match_dup 1)) (clobber (match_dup 2))])] { @@ -15456,28 +12055,10 @@ operands[1] = gen_highpart (SImode, operands[3]); }) -(define_expand "paritysi2" - [(set (match_operand:SI 0 "register_operand" "") - (parity:SI (match_operand:SI 1 "register_operand" "")))] - "! TARGET_POPCNT" -{ - rtx scratch = gen_reg_rtx (QImode); - rtx cond; - - emit_insn (gen_paritysi2_cmp (NULL_RTX, NULL_RTX, operands[1])); - - cond = gen_rtx_fmt_ee (ORDERED, QImode, - gen_rtx_REG (CCmode, FLAGS_REG), - const0_rtx); - emit_insn (gen_rtx_SET (VOIDmode, scratch, cond)); - - emit_insn (gen_zero_extendqisi2 (operands[0], scratch)); - DONE; -}) - (define_insn_and_split "paritysi2_cmp" [(set (reg:CC FLAGS_REG) - (parity:CC (match_operand:SI 2 "register_operand" "0"))) + (unspec:CC [(match_operand:SI 2 "register_operand" "0")] + UNSPEC_PARITY)) (clobber (match_scratch:SI 0 "=r")) (clobber (match_scratch:HI 1 "=&Q"))] "! TARGET_POPCNT" @@ -15489,7 +12070,7 @@ (clobber (reg:CC FLAGS_REG))]) (parallel [(set (reg:CC FLAGS_REG) - (parity:CC (match_dup 1))) + (unspec:CC [(match_dup 1)] UNSPEC_PARITY)) (clobber (match_dup 1))])] { operands[3] = gen_lowpart (HImode, operands[2]); @@ -15500,20 +12081,13 @@ (define_insn "*parityhi2_cmp" [(set (reg:CC FLAGS_REG) - (parity:CC (match_operand:HI 1 "register_operand" "0"))) + (unspec:CC [(match_operand:HI 1 "register_operand" "0")] + UNSPEC_PARITY)) (clobber (match_scratch:HI 0 "=Q"))] "! TARGET_POPCNT" "xor{b}\t{%h0, %b0|%b0, %h0}" [(set_attr "length" "2") (set_attr "mode" "HI")]) - -(define_insn "*parityqi2_cmp" - [(set (reg:CC FLAGS_REG) - (parity:CC (match_operand:QI 0 "register_operand" "q")))] - "! TARGET_POPCNT" - "test{b}\t%0, %0" - [(set_attr "length" "2") - (set_attr "mode" "QI")]) ;; Thread-local storage patterns for ELF. ;; @@ -15530,25 +12104,10 @@ (clobber (match_scratch:SI 5 "=c")) (clobber (reg:CC FLAGS_REG))] "!TARGET_64BIT && TARGET_GNU_TLS" - "lea{l}\t{%a2@TLSGD(,%1,1), %0|%0, %a2@TLSGD[%1*1]}\;call\t%P3" + "lea{l}\t{%a2@tlsgd(,%1,1), %0|%0, %a2@tlsgd[%1*1]}\;call\t%P3" [(set_attr "type" "multi") (set_attr "length" "12")]) -(define_insn "*tls_global_dynamic_32_sun" - [(set (match_operand:SI 0 "register_operand" "=a") - (unspec:SI [(match_operand:SI 1 "register_operand" "b") - (match_operand:SI 2 "tls_symbolic_operand" "") - (match_operand:SI 3 "call_insn_operand" "")] - UNSPEC_TLS_GD)) - (clobber (match_scratch:SI 4 "=d")) - (clobber (match_scratch:SI 5 "=c")) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && TARGET_SUN_TLS" - "lea{l}\t{%a2@DTLNDX(%1), %4|%4, %a2@DTLNDX[%1]} - push{l}\t%4\;call\t%a2@TLSPLT\;pop{l}\t%4\;nop" - [(set_attr "type" "multi") - (set_attr "length" "14")]) - (define_expand "tls_global_dynamic_32" [(parallel [(set (match_operand:SI 0 "register_operand" "") (unspec:SI @@ -15584,7 +12143,7 @@ (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] UNSPEC_TLS_GD)] "TARGET_64BIT" - { return ASM_BYTE "0x66\n\tlea{q}\t{%a1@TLSGD(%%rip), %%rdi|rdi, %a1@TLSGD[rip]}\n" ASM_SHORT "0x6666\n\trex64\n\tcall\t%P2"; } + { return ASM_BYTE "0x66\n\tlea{q}\t{%a1@tlsgd(%%rip), %%rdi|rdi, %a1@tlsgd[rip]}\n" ASM_SHORT "0x6666\n\trex64\n\tcall\t%P2"; } [(set_attr "type" "multi") (set_attr "length" "16")]) @@ -15613,24 +12172,10 @@ (clobber (match_scratch:SI 4 "=c")) (clobber (reg:CC FLAGS_REG))] "!TARGET_64BIT && TARGET_GNU_TLS" - "lea{l}\t{%&@TLSLDM(%1), %0|%0, %&@TLSLDM[%1]}\;call\t%P2" + "lea{l}\t{%&@tlsldm(%1), %0|%0, %&@tlsldm[%1]}\;call\t%P2" [(set_attr "type" "multi") (set_attr "length" "11")]) -(define_insn "*tls_local_dynamic_base_32_sun" - [(set (match_operand:SI 0 "register_operand" "=a") - (unspec:SI [(match_operand:SI 1 "register_operand" "b") - (match_operand:SI 2 "call_insn_operand" "")] - UNSPEC_TLS_LD_BASE)) - (clobber (match_scratch:SI 3 "=d")) - (clobber (match_scratch:SI 4 "=c")) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && TARGET_SUN_TLS" - "lea{l}\t{%&@TMDNX(%1), %3|%3, %&@TMDNX[%1]} - push{l}\t%3\;call\t%&@TLSPLT\;pop{l}\t%3" - [(set_attr "type" "multi") - (set_attr "length" "13")]) - (define_expand "tls_local_dynamic_base_32" [(parallel [(set (match_operand:SI 0 "register_operand" "") (unspec:SI [(match_dup 1) (match_dup 2)] @@ -15662,7 +12207,7 @@ (match_operand:DI 2 "" ""))) (unspec:DI [(const_int 0)] UNSPEC_TLS_LD_BASE)] "TARGET_64BIT" - "lea{q}\t{%&@TLSLD(%%rip), %%rdi|rdi, %&@TLSLD[rip]}\;call\t%P1" + "lea{q}\t{%&@tlsld(%%rip), %%rdi|rdi, %&@tlsld[rip]}\;call\t%P1" [(set_attr "type" "multi") (set_attr "length" "12")]) @@ -16501,6 +13046,8 @@ (use (match_operand:MODEF 2 "general_operand" ""))] "TARGET_USE_FANCY_MATH_387" { + rtx (*gen_truncxf) (rtx, rtx); + rtx label = gen_label_rtx (); rtx op1 = gen_reg_rtx (XFmode); @@ -16517,10 +13064,11 @@ /* Truncate the result properly for strict SSE math. */ if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH && !TARGET_MIX_SSE_I387) - emit_insn (gen_truncxf2 (operands[0], op1)); + gen_truncxf = gen_truncxf2; else - emit_insn (gen_truncxf2_i387_noop_unspec (operands[0], op1)); + gen_truncxf = gen_truncxf2_i387_noop_unspec; + emit_insn (gen_truncxf (operands[0], op1)); DONE; }) @@ -16569,6 +13117,8 @@ (use (match_operand:MODEF 2 "general_operand" ""))] "TARGET_USE_FANCY_MATH_387" { + rtx (*gen_truncxf) (rtx, rtx); + rtx label = gen_label_rtx (); rtx op1 = gen_reg_rtx (XFmode); @@ -16586,10 +13136,11 @@ /* Truncate the result properly for strict SSE math. */ if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH && !TARGET_MIX_SSE_I387) - emit_insn (gen_truncxf2 (operands[0], op1)); + gen_truncxf = gen_truncxf2; else - emit_insn (gen_truncxf2_i387_noop_unspec (operands[0], op1)); + gen_truncxf = gen_truncxf2_i387_noop_unspec; + emit_insn (gen_truncxf (operands[0], op1)); DONE; }) @@ -18821,7 +15372,7 @@ (mem:BLK (match_dup 4))) (use (match_dup 5))] "TARGET_64BIT" - "rep movsq" + "rep{%;} movsq" [(set_attr "type" "str") (set_attr "prefix_rep" "1") (set_attr "memory" "both") @@ -18840,7 +15391,7 @@ (mem:BLK (match_dup 4))) (use (match_dup 5))] "!TARGET_64BIT" - "rep movs{l|d}" + "rep{%;} movs{l|d}" [(set_attr "type" "str") (set_attr "prefix_rep" "1") (set_attr "memory" "both") @@ -18859,7 +15410,7 @@ (mem:BLK (match_dup 4))) (use (match_dup 5))] "TARGET_64BIT" - "rep movs{l|d}" + "rep{%;} movs{l|d}" [(set_attr "type" "str") (set_attr "prefix_rep" "1") (set_attr "memory" "both") @@ -18876,7 +15427,7 @@ (mem:BLK (match_dup 4))) (use (match_dup 5))] "!TARGET_64BIT" - "rep movsb" + "rep{%;} movsb" [(set_attr "type" "str") (set_attr "prefix_rep" "1") (set_attr "memory" "both") @@ -18893,7 +15444,7 @@ (mem:BLK (match_dup 4))) (use (match_dup 5))] "TARGET_64BIT" - "rep movsb" + "rep{%;} movsb" [(set_attr "type" "str") (set_attr "prefix_rep" "1") (set_attr "memory" "both") @@ -19074,7 +15625,7 @@ (use (match_operand:DI 2 "register_operand" "a")) (use (match_dup 4))] "TARGET_64BIT" - "rep stosq" + "rep{%;} stosq" [(set_attr "type" "str") (set_attr "prefix_rep" "1") (set_attr "memory" "store") @@ -19091,7 +15642,7 @@ (use (match_operand:SI 2 "register_operand" "a")) (use (match_dup 4))] "!TARGET_64BIT" - "rep stos{l|d}" + "rep{%;} stos{l|d}" [(set_attr "type" "str") (set_attr "prefix_rep" "1") (set_attr "memory" "store") @@ -19108,7 +15659,7 @@ (use (match_operand:SI 2 "register_operand" "a")) (use (match_dup 4))] "TARGET_64BIT" - "rep stos{l|d}" + "rep{%;} stos{l|d}" [(set_attr "type" "str") (set_attr "prefix_rep" "1") (set_attr "memory" "store") @@ -19124,7 +15675,7 @@ (use (match_operand:QI 2 "register_operand" "a")) (use (match_dup 4))] "!TARGET_64BIT" - "rep stosb" + "rep{%;} stosb" [(set_attr "type" "str") (set_attr "prefix_rep" "1") (set_attr "memory" "store") @@ -19140,7 +15691,7 @@ (use (match_operand:QI 2 "register_operand" "a")) (use (match_dup 4))] "TARGET_64BIT" - "rep stosb" + "rep{%;} stosb" [(set_attr "type" "str") (set_attr "prefix_rep" "1") (set_attr "memory" "store") @@ -19195,10 +15746,12 @@ } else { - if (TARGET_64BIT) - emit_insn (gen_cmpdi_1_rex64 (countreg, countreg)); - else - emit_insn (gen_cmpsi_1 (countreg, countreg)); + rtx (*gen_cmp) (rtx, rtx); + + gen_cmp = (TARGET_64BIT + ? gen_cmpdi_1 : gen_cmpsi_1); + + emit_insn (gen_cmp (countreg, countreg)); emit_insn (gen_cmpstrnqi_1 (addr1, addr2, countreg, align, operands[1], operands[2])); } @@ -19253,7 +15806,7 @@ (clobber (match_operand:SI 1 "register_operand" "=D")) (clobber (match_operand:SI 2 "register_operand" "=c"))] "!TARGET_64BIT" - "repz cmpsb" + "repz{%;} cmpsb" [(set_attr "type" "str") (set_attr "mode" "QI") (set_attr "prefix_rep" "1")]) @@ -19268,7 +15821,7 @@ (clobber (match_operand:DI 1 "register_operand" "=D")) (clobber (match_operand:DI 2 "register_operand" "=c"))] "TARGET_64BIT" - "repz cmpsb" + "repz{%;} cmpsb" [(set_attr "type" "str") (set_attr "mode" "QI") (set_attr "prefix_rex" "0") @@ -19304,7 +15857,7 @@ (clobber (match_operand:SI 1 "register_operand" "=D")) (clobber (match_operand:SI 2 "register_operand" "=c"))] "!TARGET_64BIT" - "repz cmpsb" + "repz{%;} cmpsb" [(set_attr "type" "str") (set_attr "mode" "QI") (set_attr "prefix_rep" "1")]) @@ -19322,7 +15875,7 @@ (clobber (match_operand:DI 1 "register_operand" "=D")) (clobber (match_operand:DI 2 "register_operand" "=c"))] "TARGET_64BIT" - "repz cmpsb" + "repz{%;} cmpsb" [(set_attr "type" "str") (set_attr "mode" "QI") (set_attr "prefix_rex" "0") @@ -19370,7 +15923,7 @@ (clobber (match_operand:SI 1 "register_operand" "=D")) (clobber (reg:CC FLAGS_REG))] "!TARGET_64BIT" - "repnz scasb" + "repnz{%;} scasb" [(set_attr "type" "str") (set_attr "mode" "QI") (set_attr "prefix_rep" "1")]) @@ -19384,7 +15937,7 @@ (clobber (match_operand:DI 1 "register_operand" "=D")) (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT" - "repnz scasb" + "repnz{%;} scasb" [(set_attr "type" "str") (set_attr "mode" "QI") (set_attr "prefix_rex" "0") @@ -19485,9 +16038,23 @@ ;; the register first winds up with `sbbl $0,reg', which is also weird. ;; So just document what we're doing explicitly. -(define_insn "x86_movcc_0_m1" +(define_expand "x86_movcc_0_m1" + [(parallel + [(set (match_operand:SWI48 0 "register_operand" "") + (if_then_else:SWI48 + (match_operator:SWI48 2 "ix86_carry_flag_operator" + [(match_operand 1 "flags_reg_operand" "") + (const_int 0)]) + (const_int -1) + (const_int 0))) + (clobber (reg:CC FLAGS_REG))])] + "" + "") + +(define_insn "*x86_movcc_0_m1" [(set (match_operand:SWI48 0 "register_operand" "=r") - (if_then_else:SWI48 (match_operand 1 "ix86_carry_flag_operator" "") + (if_then_else:SWI48 (match_operator 1 "ix86_carry_flag_operator" + [(reg FLAGS_REG) (const_int 0)]) (const_int -1) (const_int 0))) (clobber (reg:CC FLAGS_REG))] @@ -19505,7 +16072,8 @@ (define_insn "*x86_movcc_0_m1_se" [(set (match_operand:SWI48 0 "register_operand" "=r") - (sign_extract:SWI48 (match_operand 1 "ix86_carry_flag_operator" "") + (sign_extract:SWI48 (match_operator 1 "ix86_carry_flag_operator" + [(reg FLAGS_REG) (const_int 0)]) (const_int 1) (const_int 0))) (clobber (reg:CC FLAGS_REG))] @@ -19521,7 +16089,8 @@ (define_insn "*x86_movcc_0_m1_neg" [(set (match_operand:SWI48 0 "register_operand" "=r") - (neg:SWI48 (match_operand 1 "ix86_carry_flag_operator" "")))] + (neg:SWI48 (match_operator 1 "ix86_carry_flag_operator" + [(reg FLAGS_REG) (const_int 0)])))] "" "sbb{}\t%0, %0" [(set_attr "type" "alu") @@ -19639,8 +16208,10 @@ (if_then_else:SI (match_op_dup 1 [(match_dup 4) (const_int 0)]) (match_dup 7) (match_dup 8)))] - "split_di (&operands[2], 2, &operands[5], &operands[7]); - split_di (&operands[0], 1, &operands[2], &operands[3]);") +{ + split_di (&operands[2], 2, &operands[5], &operands[7]); + split_di (&operands[0], 1, &operands[2], &operands[3]); +}) (define_insn "*movxfcc_1" [(set (match_operand:XF 0 "register_operand" "=f,f") @@ -19655,6 +16226,20 @@ [(set_attr "type" "fcmov") (set_attr "mode" "XF")]) +;; All moves in XOP pcmov instructions are 128 bits and hence we restrict +;; the scalar versions to have only XMM registers as operands. + +;; XOP conditional move +(define_insn "*xop_pcmov_" + [(set (match_operand:MODEF 0 "register_operand" "=x") + (if_then_else:MODEF + (match_operand:MODEF 1 "register_operand" "x") + (match_operand:MODEF 2 "register_operand" "x") + (match_operand:MODEF 3 "register_operand" "x")))] + "TARGET_XOP" + "vpcmov\t{%1, %3, %2, %0|%0, %2, %3, %1}" + [(set_attr "type" "sse4arg")]) + ;; These versions of the min/max patterns are intentionally ignorant of ;; their behavior wrt -0.0 and NaN (via the commutative operand mark). ;; Since both the tree-level MAX_EXPR and the rtl-level SMAX operator @@ -19666,7 +16251,7 @@ (match_operand:MODEF 1 "nonimmediate_operand" "%x") (match_operand:MODEF 2 "nonimmediate_operand" "xm")))] "AVX_FLOAT_MODE_P (mode) && TARGET_SSE_MATH" - "vs\t{%2, %1, %0|%0, %1, %2}" + "vs\t{%2, %1, %0|%0, %1, %2}" [(set_attr "type" "sseadd") (set_attr "prefix" "vex") (set_attr "mode" "")]) @@ -19677,7 +16262,7 @@ (match_operand:MODEF 1 "nonimmediate_operand" "%0") (match_operand:MODEF 2 "nonimmediate_operand" "xm")))] "SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH" - "s\t{%2, %0|%0, %2}" + "s\t{%2, %0|%0, %2}" [(set_attr "type" "sseadd") (set_attr "mode" "")]) @@ -19780,95 +16365,37 @@ ;; [(set (mem (plus (reg ebp) (const_int -160000))) (const_int 0))] ;; ;; in proper program order. -(define_insn "pro_epilogue_adjust_stack_1" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (plus:SI (match_operand:SI 1 "register_operand" "0,r") - (match_operand:SI 2 "immediate_operand" "i,i"))) - (clobber (reg:CC FLAGS_REG)) - (clobber (mem:BLK (scratch)))] - "!TARGET_64BIT" -{ - switch (get_attr_type (insn)) - { - case TYPE_IMOV: - return "mov{l}\t{%1, %0|%0, %1}"; - - case TYPE_ALU: - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{l}\t{%2, %0|%0, %2}"; - } - return "add{l}\t{%2, %0|%0, %2}"; - - case TYPE_LEA: - operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); - return "lea{l}\t{%a2, %0|%0, %a2}"; - - default: - gcc_unreachable (); - } -} - [(set (attr "type") - (cond [(and (eq_attr "alternative" "0") - (eq (symbol_ref "TARGET_OPT_AGU") (const_int 0))) - (const_string "alu") - (match_operand:SI 2 "const0_operand" "") - (const_string "imov") - ] - (const_string "lea"))) - (set (attr "length_immediate") - (cond [(eq_attr "type" "imov") - (const_string "0") - (and (eq_attr "type" "alu") - (match_operand 2 "const128_operand" "")) - (const_string "1") - ] - (const_string "*"))) - (set_attr "mode" "SI")]) -(define_insn "pro_epilogue_adjust_stack_rex64" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (plus:DI (match_operand:DI 1 "register_operand" "0,r") - (match_operand:DI 2 "x86_64_immediate_operand" "e,e"))) +(define_insn "pro_epilogue_adjust_stack__1" + [(set (match_operand:P 0 "register_operand" "=r,r") + (plus:P (match_operand:P 1 "register_operand" "0,r") + (match_operand:P 2 "" ","))) (clobber (reg:CC FLAGS_REG)) (clobber (mem:BLK (scratch)))] - "TARGET_64BIT" + "" { switch (get_attr_type (insn)) { case TYPE_IMOV: - return "mov{q}\t{%1, %0|%0, %1}"; + return "mov{}\t{%1, %0|%0, %1}"; case TYPE_ALU: - if (CONST_INT_P (operands[2]) - /* Avoid overflows. */ - && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1))) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{q}\t{%2, %0|%0, %2}"; - } - return "add{q}\t{%2, %0|%0, %2}"; + gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (x86_maybe_negate_const_int (&operands[2], mode)) + return "sub{}\t{%2, %0|%0, %2}"; - case TYPE_LEA: - operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); - return "lea{q}\t{%a2, %0|%0, %a2}"; + return "add{}\t{%2, %0|%0, %2}"; default: - gcc_unreachable (); + operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); + return "lea{}\t{%a2, %0|%0, %a2}"; } } [(set (attr "type") (cond [(and (eq_attr "alternative" "0") - (eq (symbol_ref "TARGET_OPT_AGU") (const_int 0))) + (eq (symbol_ref "TARGET_OPT_AGU") (const_int 0))) (const_string "alu") - (match_operand:DI 2 "const0_operand" "") + (match_operand: 2 "const0_operand" "") (const_string "imov") ] (const_string "lea"))) @@ -19880,9 +16407,9 @@ (const_string "1") ] (const_string "*"))) - (set_attr "mode" "DI")]) + (set_attr "mode" "")]) -(define_insn "pro_epilogue_adjust_stack_rex64_2" +(define_insn "pro_epilogue_adjust_stack_di_2" [(set (match_operand:DI 0 "register_operand" "=r,r") (plus:DI (match_operand:DI 1 "register_operand" "0,r") (match_operand:DI 3 "immediate_operand" "i,i"))) @@ -19913,7 +16440,7 @@ UNSPECV_STACK_PROBE)) (set (reg:SI SP_REG) (minus:SI (reg:SI SP_REG) (match_dup 1))) (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && TARGET_STACK_PROBE" + "!TARGET_64BIT && ix86_target_stack_probe ()" "call\t___chkstk" [(set_attr "type" "multi") (set_attr "length" "5")]) @@ -19926,7 +16453,7 @@ (clobber (reg:DI R10_REG)) (clobber (reg:DI R11_REG)) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && TARGET_STACK_PROBE" + "TARGET_64BIT && ix86_target_stack_probe ()" "call\t___chkstk" [(set_attr "type" "multi") (set_attr "length" "5")]) @@ -19934,7 +16461,7 @@ (define_expand "allocate_stack" [(match_operand 0 "register_operand" "") (match_operand 1 "general_operand" "")] - "TARGET_STACK_PROBE" + "ix86_target_stack_probe ()" { rtx x; @@ -19952,18 +16479,57 @@ } else { - x = copy_to_mode_reg (Pmode, operands[1]); + rtx (*gen_allocate_stack_worker) (rtx, rtx); + if (TARGET_64BIT) - x = gen_allocate_stack_worker_64 (x, x); + gen_allocate_stack_worker = gen_allocate_stack_worker_64; else - x = gen_allocate_stack_worker_32 (x, x); - emit_insn (x); + gen_allocate_stack_worker = gen_allocate_stack_worker_32; + + x = copy_to_mode_reg (Pmode, operands[1]); + emit_insn (gen_allocate_stack_worker (x, x)); } emit_move_insn (operands[0], virtual_stack_dynamic_rtx); DONE; }) +;; Use IOR for stack probes, this is shorter. +(define_expand "probe_stack" + [(match_operand 0 "memory_operand" "")] + "" +{ + rtx (*gen_ior3) (rtx, rtx, rtx); + + gen_ior3 = (GET_MODE (operands[0]) == DImode + ? gen_iordi3 : gen_iorsi3); + + emit_insn (gen_ior3 (operands[0], operands[0], const0_rtx)); + DONE; +}) + +(define_insn "adjust_stack_and_probe" + [(set (match_operand:P 0 "register_operand" "=r") + (unspec_volatile:P [(match_operand:P 1 "register_operand" "0")] + UNSPECV_PROBE_STACK_RANGE)) + (set (reg:P SP_REG) + (minus:P (reg:P SP_REG) (match_operand:P 2 "const_int_operand" "n"))) + (clobber (reg:CC FLAGS_REG)) + (clobber (mem:BLK (scratch)))] + "" + "* return output_adjust_stack_and_probe (operands[0]);" + [(set_attr "type" "multi")]) + +(define_insn "probe_stack_range" + [(set (match_operand:P 0 "register_operand" "=r") + (unspec_volatile:P [(match_operand:P 1 "register_operand" "0") + (match_operand:P 2 "const_int_operand" "n")] + UNSPECV_PROBE_STACK_RANGE)) + (clobber (reg:CC FLAGS_REG))] + "" + "* return output_probe_stack_range (operands[0], operands[2]);" + [(set_attr "type" "multi")]) + (define_expand "builtin_setjmp_receiver" [(label_ref (match_operand 0 "" ""))] "!TARGET_64BIT && flag_pic" @@ -20467,7 +17033,9 @@ [(match_dup 0) (match_operand:SI 1 "nonmemory_operand" "")])) (clobber (reg:CC FLAGS_REG))])] - "optimize_insn_for_speed_p () && ! TARGET_READ_MODIFY_WRITE" + "optimize_insn_for_speed_p () && ! TARGET_READ_MODIFY_WRITE + /* Do not split stack checking probes. */ + && GET_CODE (operands[3]) != IOR && operands[1] != const0_rtx" [(set (match_dup 2) (match_dup 0)) (parallel [(set (match_dup 2) (match_op_dup 3 [(match_dup 2) (match_dup 1)])) @@ -20482,7 +17050,9 @@ [(match_operand:SI 1 "nonmemory_operand" "") (match_dup 0)])) (clobber (reg:CC FLAGS_REG))])] - "optimize_insn_for_speed_p () && ! TARGET_READ_MODIFY_WRITE" + "optimize_insn_for_speed_p () && ! TARGET_READ_MODIFY_WRITE + /* Do not split stack checking probes. */ + && GET_CODE (operands[3]) != IOR && operands[1] != const0_rtx" [(set (match_dup 2) (match_dup 0)) (parallel [(set (match_dup 2) (match_op_dup 3 [(match_dup 1) (match_dup 2)])) @@ -20868,7 +17438,7 @@ [(set (match_dup 0) (plus:SI (mult:SI (match_dup 1) (match_dup 2)) (match_dup 1)))] - { operands[2] = GEN_INT (INTVAL (operands[2]) - 1); }) + "operands[2] = GEN_INT (INTVAL (operands[2]) - 1);") (define_peephole2 [(parallel @@ -20884,7 +17454,7 @@ (set (match_dup 0) (plus:SI (mult:SI (match_dup 0) (match_dup 2)) (match_dup 0)))] - { operands[2] = GEN_INT (INTVAL (operands[2]) - 1); }) + "operands[2] = GEN_INT (INTVAL (operands[2]) - 1);") (define_peephole2 [(parallel @@ -20899,7 +17469,7 @@ [(set (match_dup 0) (plus:DI (mult:DI (match_dup 1) (match_dup 2)) (match_dup 1)))] - { operands[2] = GEN_INT (INTVAL (operands[2]) - 1); }) + "operands[2] = GEN_INT (INTVAL (operands[2]) - 1);") (define_peephole2 [(parallel @@ -20916,7 +17486,7 @@ (set (match_dup 0) (plus:DI (mult:DI (match_dup 0) (match_dup 2)) (match_dup 0)))] - { operands[2] = GEN_INT (INTVAL (operands[2]) - 1); }) + "operands[2] = GEN_INT (INTVAL (operands[2]) - 1);") ;; Imul $32bit_imm, mem, reg is vector decoded, while ;; imul $32bit_imm, reg, reg is direct decoded. @@ -20931,7 +17501,7 @@ [(set (match_dup 3) (match_dup 1)) (parallel [(set (match_dup 0) (mult:DI (match_dup 3) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] -"") + "") (define_peephole2 [(match_scratch:SI 3 "r") @@ -20944,7 +17514,7 @@ [(set (match_dup 3) (match_dup 1)) (parallel [(set (match_dup 0) (mult:SI (match_dup 3) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] -"") + "") (define_peephole2 [(match_scratch:SI 3 "r") @@ -20956,9 +17526,10 @@ "TARGET_SLOW_IMUL_IMM32_MEM && optimize_insn_for_speed_p () && !satisfies_constraint_K (operands[2])" [(set (match_dup 3) (match_dup 1)) - (parallel [(set (match_dup 0) (zero_extend:DI (mult:SI (match_dup 3) (match_dup 2)))) + (parallel [(set (match_dup 0) + (zero_extend:DI (mult:SI (match_dup 3) (match_dup 2)))) (clobber (reg:CC FLAGS_REG))])] -"") + "") ;; imul $8/16bit_imm, regmem, reg is vector decoded. ;; Convert it into imul reg, reg @@ -21024,15 +17595,14 @@ ;; leal (%edx,%eax,4), %eax (define_peephole2 - [(parallel [(set (match_operand 0 "register_operand" "") + [(match_scratch:P 5 "r") + (parallel [(set (match_operand 0 "register_operand" "") (ashift (match_operand 1 "register_operand" "") (match_operand 2 "const_int_operand" ""))) (clobber (reg:CC FLAGS_REG))]) - (set (match_operand 3 "register_operand") - (match_operand 4 "x86_64_general_operand" "")) - (parallel [(set (match_operand 5 "register_operand" "") - (plus (match_operand 6 "register_operand" "") - (match_operand 7 "register_operand" ""))) + (parallel [(set (match_operand 3 "register_operand" "") + (plus (match_dup 0) + (match_operand 4 "x86_64_general_operand" ""))) (clobber (reg:CC FLAGS_REG))])] "INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) <= 3 /* Validate MODE for lea. */ @@ -21041,31 +17611,27 @@ || GET_MODE (operands[0]) == HImode)) || GET_MODE (operands[0]) == SImode || (TARGET_64BIT && GET_MODE (operands[0]) == DImode)) + && (rtx_equal_p (operands[0], operands[3]) + || peep2_reg_dead_p (2, operands[0])) /* We reorder load and the shift. */ - && !rtx_equal_p (operands[1], operands[3]) - && !reg_overlap_mentioned_p (operands[0], operands[4]) - /* Last PLUS must consist of operand 0 and 3. */ - && !rtx_equal_p (operands[0], operands[3]) - && (rtx_equal_p (operands[3], operands[6]) - || rtx_equal_p (operands[3], operands[7])) - && (rtx_equal_p (operands[0], operands[6]) - || rtx_equal_p (operands[0], operands[7])) - /* The intermediate operand 0 must die or be same as output. */ - && (rtx_equal_p (operands[0], operands[5]) - || peep2_reg_dead_p (3, operands[0]))" - [(set (match_dup 3) (match_dup 4)) + && !reg_overlap_mentioned_p (operands[0], operands[4])" + [(set (match_dup 5) (match_dup 4)) (set (match_dup 0) (match_dup 1))] { - enum machine_mode mode = GET_MODE (operands[5]) == DImode ? DImode : SImode; + enum machine_mode mode = GET_MODE (operands[1]) == DImode ? DImode : SImode; int scale = 1 << INTVAL (operands[2]); rtx index = gen_lowpart (Pmode, operands[1]); - rtx base = gen_lowpart (Pmode, operands[3]); - rtx dest = gen_lowpart (mode, operands[5]); + rtx base = gen_lowpart (Pmode, operands[5]); + rtx dest = gen_lowpart (mode, operands[3]); operands[1] = gen_rtx_PLUS (Pmode, base, gen_rtx_MULT (Pmode, index, GEN_INT (scale))); + operands[5] = base; if (mode != Pmode) - operands[1] = gen_rtx_SUBREG (mode, operands[1], 0); + { + operands[1] = gen_rtx_SUBREG (mode, operands[1], 0); + operands[5] = gen_rtx_SUBREG (mode, operands[5], 0); + } operands[0] = dest; }) @@ -21076,8 +17642,9 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:SI 1 "constant_call_address_operand" "")) (match_operand:SI 2 "" ""))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) - (match_operand:SI 3 "immediate_operand" "")))] + (set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI 3 "immediate_operand" "")))] "!TARGET_64BIT" { if (SIBLING_CALL_P (insn)) @@ -21089,11 +17656,12 @@ (define_insn "*call_value_pop_1" [(set (match_operand 0 "" "") - (call (mem:QI (match_operand:SI 1 "call_insn_operand" "rsm")) + (call (mem:QI (match_operand:SI 1 "call_insn_operand" "lsm")) (match_operand:SI 2 "" ""))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) - (match_operand:SI 3 "immediate_operand" "i")))] - "!SIBLING_CALL_P (insn) && !TARGET_64BIT" + (set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI 3 "immediate_operand" "i")))] + "!TARGET_64BIT && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[1], Pmode)) return "call\t%P1"; @@ -21105,9 +17673,10 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,U")) (match_operand:SI 2 "" ""))) - (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) - (match_operand:SI 3 "immediate_operand" "i,i")))] - "SIBLING_CALL_P (insn) && !TARGET_64BIT" + (set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI 3 "immediate_operand" "i,i")))] + "!TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P1 jmp\t%A1" @@ -21156,7 +17725,7 @@ (clobber (reg:TI XMM15_REG)) (clobber (reg:DI SI_REG)) (clobber (reg:DI DI_REG))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && !SIBLING_CALL_P (insn)" { if (SIBLING_CALL_P (insn)) return "jmp\t%P1"; @@ -21167,9 +17736,9 @@ (define_insn "*call_value_1" [(set (match_operand 0 "" "") - (call (mem:QI (match_operand:SI 1 "call_insn_operand" "rsm")) + (call (mem:QI (match_operand:SI 1 "call_insn_operand" "lsm")) (match_operand:SI 2 "" "")))] - "!SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[1], Pmode)) return "call\t%P1"; @@ -21181,7 +17750,7 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,U")) (match_operand:SI 2 "" "")))] - "SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P1 jmp\t%A1" @@ -21191,7 +17760,7 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:DI 1 "call_insn_operand" "rsm")) (match_operand:DI 2 "" "")))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT + "TARGET_64BIT && !SIBLING_CALL_P (insn) && ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC" { if (constant_call_address_operand (operands[1], Pmode)) @@ -21205,19 +17774,19 @@ (call (mem:QI (match_operand:DI 1 "call_insn_operand" "rsm")) (match_operand:DI 2 "" ""))) (unspec [(const_int 0)] UNSPEC_MS_TO_SYSV_CALL) - (clobber (reg:TI 27)) - (clobber (reg:TI 28)) - (clobber (reg:TI 45)) - (clobber (reg:TI 46)) - (clobber (reg:TI 47)) - (clobber (reg:TI 48)) - (clobber (reg:TI 49)) - (clobber (reg:TI 50)) - (clobber (reg:TI 51)) - (clobber (reg:TI 52)) + (clobber (reg:TI XMM6_REG)) + (clobber (reg:TI XMM7_REG)) + (clobber (reg:TI XMM8_REG)) + (clobber (reg:TI XMM9_REG)) + (clobber (reg:TI XMM10_REG)) + (clobber (reg:TI XMM11_REG)) + (clobber (reg:TI XMM12_REG)) + (clobber (reg:TI XMM13_REG)) + (clobber (reg:TI XMM14_REG)) + (clobber (reg:TI XMM15_REG)) (clobber (reg:DI SI_REG)) (clobber (reg:DI DI_REG))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[1], Pmode)) return "call\t%P1"; @@ -21229,7 +17798,7 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:DI 1 "call_insn_operand" "rm")) (match_operand:DI 2 "" "")))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && !SIBLING_CALL_P (insn)" "call\t%A1" [(set_attr "type" "callv")]) @@ -21237,7 +17806,7 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:DI 1 "sibcall_insn_operand" "s,U")) (match_operand:DI 2 "" "")))] - "SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P1 jmp\t%A1" @@ -21254,74 +17823,6 @@ { return ASM_SHORT "0x0b0f"; } [(set_attr "length" "2")]) -(define_expand "sse_prologue_save" - [(parallel [(set (match_operand:BLK 0 "" "") - (unspec:BLK [(reg:DI 21) - (reg:DI 22) - (reg:DI 23) - (reg:DI 24) - (reg:DI 25) - (reg:DI 26) - (reg:DI 27) - (reg:DI 28)] UNSPEC_SSE_PROLOGUE_SAVE)) - (use (match_operand:DI 1 "register_operand" "")) - (use (match_operand:DI 2 "immediate_operand" "")) - (use (label_ref:DI (match_operand 3 "" "")))])] - "TARGET_64BIT" - "") - -(define_insn "*sse_prologue_save_insn" - [(set (mem:BLK (plus:DI (match_operand:DI 0 "register_operand" "R") - (match_operand:DI 4 "const_int_operand" "n"))) - (unspec:BLK [(reg:DI 21) - (reg:DI 22) - (reg:DI 23) - (reg:DI 24) - (reg:DI 25) - (reg:DI 26) - (reg:DI 27) - (reg:DI 28)] UNSPEC_SSE_PROLOGUE_SAVE)) - (use (match_operand:DI 1 "register_operand" "r")) - (use (match_operand:DI 2 "const_int_operand" "i")) - (use (label_ref:DI (match_operand 3 "" "X")))] - "TARGET_64BIT - && INTVAL (operands[4]) + X86_64_SSE_REGPARM_MAX * 16 - 16 < 128 - && INTVAL (operands[4]) + INTVAL (operands[2]) * 16 >= -128" -{ - int i; - operands[0] = gen_rtx_MEM (Pmode, - gen_rtx_PLUS (Pmode, operands[0], operands[4])); - /* VEX instruction with a REX prefix will #UD. */ - if (TARGET_AVX && GET_CODE (XEXP (operands[0], 0)) != PLUS) - gcc_unreachable (); - - output_asm_insn ("jmp\t%A1", operands); - for (i = X86_64_SSE_REGPARM_MAX - 1; i >= INTVAL (operands[2]); i--) - { - operands[4] = adjust_address (operands[0], DImode, i*16); - operands[5] = gen_rtx_REG (TImode, SSE_REGNO (i)); - PUT_MODE (operands[4], TImode); - if (GET_CODE (XEXP (operands[0], 0)) != PLUS) - output_asm_insn ("rex", operands); - output_asm_insn ("%vmovaps\t{%5, %4|%4, %5}", operands); - } - (*targetm.asm_out.internal_label) (asm_out_file, "L", - CODE_LABEL_NUMBER (operands[3])); - return ""; -} - [(set_attr "type" "other") - (set_attr "length_immediate" "0") - (set_attr "length_address" "0") - (set (attr "length") - (if_then_else - (eq (symbol_ref "TARGET_AVX") (const_int 0)) - (const_string "34") - (const_string "42"))) - (set_attr "memory" "store") - (set_attr "modrm" "0") - (set_attr "prefix" "maybe_vex") - (set_attr "mode" "DI")]) - (define_expand "prefetch" [(prefetch (match_operand 0 "address_operand" "") (match_operand:SI 1 "const_int_operand" "") @@ -21346,31 +17847,11 @@ operands[1] = const0_rtx; }) -(define_insn "*prefetch_sse" - [(prefetch (match_operand:SI 0 "address_operand" "p") - (const_int 0) - (match_operand:SI 1 "const_int_operand" ""))] - "TARGET_PREFETCH_SSE && !TARGET_64BIT" -{ - static const char * const patterns[4] = { - "prefetchnta\t%a0", "prefetcht2\t%a0", "prefetcht1\t%a0", "prefetcht0\t%a0" - }; - - int locality = INTVAL (operands[1]); - gcc_assert (locality >= 0 && locality <= 3); - - return patterns[locality]; -} - [(set_attr "type" "sse") - (set_attr "atom_sse_attr" "prefetch") - (set (attr "length_address") (symbol_ref "memory_address_length (operands[0])")) - (set_attr "memory" "none")]) - -(define_insn "*prefetch_sse_rex" - [(prefetch (match_operand:DI 0 "address_operand" "p") +(define_insn "*prefetch_sse_" + [(prefetch (match_operand:P 0 "address_operand" "p") (const_int 0) (match_operand:SI 1 "const_int_operand" ""))] - "TARGET_PREFETCH_SSE && TARGET_64BIT" + "TARGET_PREFETCH_SSE" { static const char * const patterns[4] = { "prefetchnta\t%a0", "prefetcht2\t%a0", "prefetcht1\t%a0", "prefetcht0\t%a0" @@ -21383,29 +17864,15 @@ } [(set_attr "type" "sse") (set_attr "atom_sse_attr" "prefetch") - (set (attr "length_address") (symbol_ref "memory_address_length (operands[0])")) - (set_attr "memory" "none")]) - -(define_insn "*prefetch_3dnow" - [(prefetch (match_operand:SI 0 "address_operand" "p") - (match_operand:SI 1 "const_int_operand" "n") - (const_int 3))] - "TARGET_3DNOW && !TARGET_64BIT" -{ - if (INTVAL (operands[1]) == 0) - return "prefetch\t%a0"; - else - return "prefetchw\t%a0"; -} - [(set_attr "type" "mmx") - (set (attr "length_address") (symbol_ref "memory_address_length (operands[0])")) + (set (attr "length_address") + (symbol_ref "memory_address_length (operands[0])")) (set_attr "memory" "none")]) -(define_insn "*prefetch_3dnow_rex" - [(prefetch (match_operand:DI 0 "address_operand" "p") +(define_insn "*prefetch_3dnow_" + [(prefetch (match_operand:P 0 "address_operand" "p") (match_operand:SI 1 "const_int_operand" "n") (const_int 3))] - "TARGET_3DNOW && TARGET_64BIT" + "TARGET_3DNOW" { if (INTVAL (operands[1]) == 0) return "prefetch\t%a0"; @@ -21413,7 +17880,8 @@ return "prefetchw\t%a0"; } [(set_attr "type" "mmx") - (set (attr "length_address") (symbol_ref "memory_address_length (operands[0])")) + (set (attr "length_address") + (symbol_ref "memory_address_length (operands[0])")) (set_attr "memory" "none")]) (define_expand "stack_protect_set" @@ -21457,7 +17925,8 @@ (define_insn "stack_tls_protect_set_si" [(set (match_operand:SI 0 "memory_operand" "=m") - (unspec:SI [(match_operand:SI 1 "const_int_operand" "i")] UNSPEC_SP_TLS_SET)) + (unspec:SI [(match_operand:SI 1 "const_int_operand" "i")] + UNSPEC_SP_TLS_SET)) (set (match_scratch:SI 2 "=&r") (const_int 0)) (clobber (reg:CC FLAGS_REG))] "" @@ -21466,7 +17935,8 @@ (define_insn "stack_tls_protect_set_di" [(set (match_operand:DI 0 "memory_operand" "=m") - (unspec:DI [(match_operand:DI 1 "const_int_operand" "i")] UNSPEC_SP_TLS_SET)) + (unspec:DI [(match_operand:DI 1 "const_int_operand" "i")] + UNSPEC_SP_TLS_SET)) (set (match_scratch:DI 2 "=&r") (const_int 0)) (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT" @@ -21556,18 +18026,14 @@ } [(set_attr "type" "multi")]) -(define_mode_iterator CRC32MODE [QI HI SI]) -(define_mode_attr crc32modesuffix [(QI "b") (HI "w") (SI "l")]) -(define_mode_attr crc32modeconstraint [(QI "qm") (HI "rm") (SI "rm")]) - (define_insn "sse4_2_crc32" [(set (match_operand:SI 0 "register_operand" "=r") (unspec:SI [(match_operand:SI 1 "register_operand" "0") - (match_operand:CRC32MODE 2 "nonimmediate_operand" "")] + (match_operand:SWI124 2 "nonimmediate_operand" "m")] UNSPEC_CRC32))] "TARGET_SSE4_2 || TARGET_CRC32" - "crc32\t{%2, %0|%0, %2}" + "crc32{}\t{%2, %0|%0, %2}" [(set_attr "type" "sselog1") (set_attr "prefix_rep" "1") (set_attr "prefix_extra" "1") @@ -21588,7 +18054,7 @@ (match_operand:DI 2 "nonimmediate_operand" "rm")] UNSPEC_CRC32))] "TARGET_64BIT && (TARGET_SSE4_2 || TARGET_CRC32)" - "crc32q\t{%2, %0|%0, %2}" + "crc32{q}\t{%2, %0|%0, %2}" [(set_attr "type" "sselog1") (set_attr "prefix_rep" "1") (set_attr "prefix_extra" "1") @@ -21757,6 +18223,158 @@ [(set_attr "type" "other") (set_attr "length" "3")]) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; LWP instructions +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define_expand "lwp_llwpcb" + [(unspec_volatile [(match_operand 0 "register_operand" "r")] + UNSPECV_LLWP_INTRINSIC)] + "TARGET_LWP" + "") + +(define_insn "*lwp_llwpcb1" + [(unspec_volatile [(match_operand:P 0 "register_operand" "r")] + UNSPECV_LLWP_INTRINSIC)] + "TARGET_LWP" + "llwpcb\t%0" + [(set_attr "type" "lwp") + (set_attr "mode" "") + (set_attr "length" "5")]) + +(define_expand "lwp_slwpcb" + [(set (match_operand 0 "register_operand" "=r") + (unspec_volatile [(const_int 0)] UNSPECV_SLWP_INTRINSIC))] + "TARGET_LWP" + { + if (TARGET_64BIT) + emit_insn (gen_lwp_slwpcbdi (operands[0])); + else + emit_insn (gen_lwp_slwpcbsi (operands[0])); + DONE; + }) + +(define_insn "lwp_slwpcb" + [(set (match_operand:P 0 "register_operand" "=r") + (unspec_volatile:P [(const_int 0)] UNSPECV_SLWP_INTRINSIC))] + "TARGET_LWP" + "slwpcb\t%0" + [(set_attr "type" "lwp") + (set_attr "mode" "") + (set_attr "length" "5")]) + +(define_expand "lwp_lwpval3" + [(unspec_volatile [(match_operand:SWI48 1 "register_operand" "r") + (match_operand:SI 2 "nonimmediate_operand" "rm") + (match_operand:SI 3 "const_int_operand" "i")] + UNSPECV_LWPVAL_INTRINSIC)] + "TARGET_LWP" + "/* Avoid unused variable warning. */ + (void) operand0;") + +(define_insn "*lwp_lwpval3_1" + [(unspec_volatile [(match_operand:SWI48 0 "register_operand" "r") + (match_operand:SI 1 "nonimmediate_operand" "rm") + (match_operand:SI 2 "const_int_operand" "i")] + UNSPECV_LWPVAL_INTRINSIC)] + "TARGET_LWP" + "lwpval\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "lwp") + (set_attr "mode" "") + (set (attr "length") + (symbol_ref "ix86_attr_length_address_default (insn) + 9"))]) + +(define_expand "lwp_lwpins3" + [(set (reg:CCC FLAGS_REG) + (unspec_volatile:CCC [(match_operand:SWI48 1 "register_operand" "r") + (match_operand:SI 2 "nonimmediate_operand" "rm") + (match_operand:SI 3 "const_int_operand" "i")] + UNSPECV_LWPINS_INTRINSIC)) + (set (match_operand:QI 0 "nonimmediate_operand" "=qm") + (eq:QI (reg:CCC FLAGS_REG) (const_int 0)))] + "TARGET_LWP" + "") + +(define_insn "*lwp_lwpins3_1" + [(set (reg:CCC FLAGS_REG) + (unspec_volatile:CCC [(match_operand:SWI48 0 "register_operand" "r") + (match_operand:SI 1 "nonimmediate_operand" "rm") + (match_operand:SI 2 "const_int_operand" "i")] + UNSPECV_LWPINS_INTRINSIC))] + "TARGET_LWP" + "lwpins\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "lwp") + (set_attr "mode" "") + (set (attr "length") + (symbol_ref "ix86_attr_length_address_default (insn) + 9"))]) + +(define_insn "rdfsbase" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (unspec_volatile:SWI48 [(const_int 0)] UNSPECV_RDFSBASE))] + "TARGET_64BIT && TARGET_FSGSBASE" + "rdfsbase %0" + [(set_attr "type" "other") + (set_attr "prefix_extra" "2")]) + +(define_insn "rdgsbase" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (unspec_volatile:SWI48 [(const_int 0)] UNSPECV_RDGSBASE))] + "TARGET_64BIT && TARGET_FSGSBASE" + "rdgsbase %0" + [(set_attr "type" "other") + (set_attr "prefix_extra" "2")]) + +(define_insn "wrfsbase" + [(unspec_volatile [(match_operand:SWI48 0 "register_operand" "r")] + UNSPECV_WRFSBASE)] + "TARGET_64BIT && TARGET_FSGSBASE" + "wrfsbase %0" + [(set_attr "type" "other") + (set_attr "prefix_extra" "2")]) + +(define_insn "wrgsbase" + [(unspec_volatile [(match_operand:SWI48 0 "register_operand" "r")] + UNSPECV_WRGSBASE)] + "TARGET_64BIT && TARGET_FSGSBASE" + "wrgsbase %0" + [(set_attr "type" "other") + (set_attr "prefix_extra" "2")]) + +(define_expand "rdrand" + [(set (match_operand:SWI248 0 "register_operand" "=r") + (unspec_volatile:SWI248 [(const_int 0)] UNSPECV_RDRAND))] + "TARGET_RDRND" +{ + rtx retry_label, insn, ccc; + + retry_label = gen_label_rtx (); + + emit_label (retry_label); + + /* Generate rdrand. */ + emit_insn (gen_rdrand_1 (operands[0])); + + /* Retry if the carry flag isn't valid. */ + ccc = gen_rtx_REG (CCCmode, FLAGS_REG); + ccc = gen_rtx_EQ (VOIDmode, ccc, const0_rtx); + ccc = gen_rtx_IF_THEN_ELSE (VOIDmode, ccc, pc_rtx, + gen_rtx_LABEL_REF (VOIDmode, retry_label)); + insn = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, ccc)); + JUMP_LABEL (insn) = retry_label; + + DONE; +}) + +(define_insn "rdrand_1" + [(set (match_operand:SWI248 0 "register_operand" "=r") + (unspec_volatile:SWI248 [(const_int 0)] UNSPECV_RDRAND))] + "TARGET_RDRND" + "rdrand %0" + [(set_attr "type" "other") + (set_attr "prefix_extra" "1")]) + (include "mmx.md") (include "sse.md") (include "sync.md")