8206 lines
232 KiB
Markdown
8206 lines
232 KiB
Markdown
; GCC machine description for Intel X86.
|
||
;; Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000 Free Software
|
||
;; Foundation, Inc.
|
||
;; Mostly by William Schelter.
|
||
|
||
;; This file is part of GNU CC.
|
||
|
||
;; GNU CC is free software; you can redistribute it and/or modify
|
||
;; it under the terms of the GNU General Public License as published by
|
||
;; the Free Software Foundation; either version 2, or (at your option)
|
||
;; any later version.
|
||
|
||
;; GNU CC is distributed in the hope that it will be useful,
|
||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;; GNU General Public License for more details.
|
||
|
||
;; You should have received a copy of the GNU General Public License
|
||
;; along with GNU CC; see the file COPYING. If not, write to
|
||
;; the Free Software Foundation, 59 Temple Place - Suite 330,
|
||
;; Boston, MA 02111-1307, USA. */
|
||
|
||
;; The original PO technology requires these to be ordered by speed,
|
||
;; so that assigner will pick the fastest.
|
||
|
||
;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
|
||
|
||
;; Macro #define NOTICE_UPDATE_CC in file i386.h handles condition code
|
||
;; updates for most instructions.
|
||
|
||
;; Macro REG_CLASS_FROM_LETTER in file i386.h defines the register
|
||
;; constraint letters.
|
||
|
||
;; the special asm out single letter directives following a '%' are:
|
||
;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of
|
||
;; operands[1].
|
||
;; 'L' Print the opcode suffix for a 32-bit integer opcode.
|
||
;; 'W' Print the opcode suffix for a 16-bit integer opcode.
|
||
;; 'B' Print the opcode suffix for an 8-bit integer opcode.
|
||
;; 'Q' Print the opcode suffix for a 64-bit float opcode.
|
||
;; 'S' Print the opcode suffix for a 32-bit float opcode.
|
||
;; 'T' Print the opcode suffix for an 80-bit extended real XFmode float opcode.
|
||
;; 'J' Print the appropriate jump operand.
|
||
|
||
;; 'b' Print the QImode name of the register for the indicated operand.
|
||
;; %b0 would print %al if operands[0] is reg 0.
|
||
;; 'w' Likewise, print the HImode name of the register.
|
||
;; 'k' Likewise, print the SImode name of the register.
|
||
;; 'h' Print the QImode name for a "high" register, either ah, bh, ch or dh.
|
||
;; 'y' Print "st(0)" instead of "st" as a register.
|
||
|
||
;; UNSPEC usage:
|
||
;; 0 This is a `scas' operation. The mode of the UNSPEC is always SImode.
|
||
;; operand 0 is the memory address to scan.
|
||
;; operand 1 is a register containing the value to scan for. The mode
|
||
;; of the scas opcode will be the same as the mode of this operand.
|
||
;; operand 2 is the known alignment of operand 0.
|
||
;; 1 This is a `sin' operation. The mode of the UNSPEC is MODE_FLOAT.
|
||
;; operand 0 is the argument for `sin'.
|
||
;; 2 This is a `cos' operation. The mode of the UNSPEC is MODE_FLOAT.
|
||
;; operand 0 is the argument for `cos'.
|
||
;; 3 This is part of a `stack probe' operation. The mode of the UNSPEC is
|
||
;; always SImode. operand 0 is the size of the stack allocation.
|
||
;; 4 This is the source of a fake SET of the frame pointer which is used to
|
||
;; prevent insns referencing it being scheduled across the initial
|
||
;; decrement of the stack pointer.
|
||
;; 5 This is a `bsf' operation.
|
||
;; 6 This is the @GOT offset of a PIC address.
|
||
;; 7 This is the @GOTOFF offset of a PIC address.
|
||
;; 8 This is a reference to a symbol's @PLT address.
|
||
|
||
;; This shadows the processor_type enumeration, so changes must be made
|
||
;; to i386.h at the same time.
|
||
|
||
(define_attr "type"
|
||
"integer,binary,memory,test,compare,fcompare,idiv,imul,lea,fld,fpop,fpdiv,fpmul"
|
||
(const_string "integer"))
|
||
|
||
(define_attr "memory" "none,load,store"
|
||
(cond [(eq_attr "type" "idiv,lea")
|
||
(const_string "none")
|
||
|
||
(eq_attr "type" "fld")
|
||
(const_string "load")
|
||
|
||
(eq_attr "type" "test")
|
||
(if_then_else (match_operand 0 "memory_operand" "")
|
||
(const_string "load")
|
||
(const_string "none"))
|
||
|
||
(eq_attr "type" "compare,fcompare")
|
||
(if_then_else (ior (match_operand 0 "memory_operand" "")
|
||
(match_operand 1 "memory_operand" ""))
|
||
(const_string "load")
|
||
(const_string "none"))
|
||
|
||
(and (eq_attr "type" "integer,memory,fpop")
|
||
(match_operand 0 "memory_operand" ""))
|
||
(const_string "store")
|
||
|
||
(and (eq_attr "type" "integer,memory,fpop")
|
||
(match_operand 1 "memory_operand" ""))
|
||
(const_string "load")
|
||
|
||
(and (eq_attr "type" "binary,imul,fpmul,fpdiv")
|
||
(ior (match_operand 1 "memory_operand" "")
|
||
(match_operand 2 "memory_operand" "")))
|
||
(const_string "load")]
|
||
|
||
(const_string "none")))
|
||
|
||
;; Functional units
|
||
|
||
; (define_function_unit NAME MULTIPLICITY SIMULTANEITY
|
||
; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST])
|
||
|
||
; pentiumpro has a reservation station with 5 ports
|
||
; port 0 has integer, float add, integer divide, float divide, float
|
||
; multiply, and shifter units.
|
||
; port 1 has integer, and jump units.
|
||
; port 2 has the load address generation unit
|
||
; ports 3 and 4 have the store address generation units
|
||
|
||
; pentium has two integer pipelines, the main u pipe and the secondary v pipe.
|
||
; and a float pipeline
|
||
|
||
;; Floating point
|
||
|
||
(define_function_unit "fp" 1 0
|
||
(and (eq_attr "type" "fpop,fcompare") (eq_attr "cpu" "i386,i486"))
|
||
5 5)
|
||
|
||
(define_function_unit "fp" 1 0
|
||
(and (eq_attr "type" "fpop,fcompare") (eq_attr "cpu" "pentium,pentiumpro"))
|
||
3 0)
|
||
|
||
(define_function_unit "fp" 1 0
|
||
(and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentium"))
|
||
7 0)
|
||
|
||
(define_function_unit "fp" 1 0
|
||
(and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentiumpro"))
|
||
5 0)
|
||
|
||
(define_function_unit "fp" 1 0
|
||
(and (eq_attr "type" "idiv") (eq_attr "cpu" "pentiumpro"))
|
||
10 10)
|
||
|
||
(define_function_unit "fp" 1 0
|
||
(and (eq_attr "type" "imul") (eq_attr "cpu" "pentiumpro"))
|
||
6 0)
|
||
|
||
(define_function_unit "fp" 1 0
|
||
(eq_attr "type" "fpdiv")
|
||
10 10)
|
||
|
||
(define_function_unit "fp" 1 0
|
||
(and (eq_attr "type" "fld") (eq_attr "cpu" "!pentiumpro,k6"))
|
||
1 0)
|
||
|
||
;; K6 FPU is not pipelined.
|
||
(define_function_unit "fp" 1 0
|
||
(and (eq_attr "type" "fpop,fpmul,fcompare") (eq_attr "cpu" "k6"))
|
||
2 2)
|
||
|
||
;; i386 and i486 have one integer unit, which need not be modeled
|
||
|
||
(define_function_unit "integer" 2 0
|
||
(and (eq_attr "type" "integer,binary,test,compare,lea") (eq_attr "cpu" "pentium,pentiumpro"))
|
||
1 0)
|
||
|
||
(define_function_unit "integer" 2 0
|
||
(and (eq_attr "cpu" "k6")
|
||
(and (eq_attr "type" "integer,binary,test,compare")
|
||
(eq_attr "memory" "!load")))
|
||
1 0)
|
||
|
||
;; Internally, K6 converts REG OP MEM instructions into a load (2 cycles)
|
||
;; and a register operation (1 cycle).
|
||
(define_function_unit "integer" 2 0
|
||
(and (eq_attr "cpu" "k6")
|
||
(and (eq_attr "type" "integer,binary,test,compare")
|
||
(eq_attr "memory" "load")))
|
||
3 0)
|
||
|
||
;; Multiplies use one of the integer units
|
||
(define_function_unit "integer" 2 0
|
||
(and (eq_attr "cpu" "pentium") (eq_attr "type" "imul"))
|
||
11 11)
|
||
|
||
(define_function_unit "integer" 2 0
|
||
(and (eq_attr "cpu" "k6") (eq_attr "type" "imul"))
|
||
2 2)
|
||
|
||
(define_function_unit "integer" 2 0
|
||
(and (eq_attr "cpu" "pentium") (eq_attr "type" "idiv"))
|
||
25 25)
|
||
|
||
(define_function_unit "integer" 2 0
|
||
(and (eq_attr "cpu" "k6") (eq_attr "type" "idiv"))
|
||
17 17)
|
||
|
||
;; Pentium Pro and K6 have a separate load unit.
|
||
(define_function_unit "load" 1 0
|
||
(and (eq_attr "cpu" "pentiumpro") (eq_attr "memory" "load"))
|
||
3 0)
|
||
|
||
(define_function_unit "load" 1 0
|
||
(and (eq_attr "cpu" "k6") (eq_attr "memory" "load"))
|
||
2 0)
|
||
|
||
;; Pentium Pro and K6 have a separate store unit.
|
||
(define_function_unit "store" 1 0
|
||
(and (eq_attr "cpu" "pentiumpro,k6") (eq_attr "memory" "store"))
|
||
1 0)
|
||
|
||
;; lea executes in the K6 store unit with 1 cycle latency
|
||
(define_function_unit "store" 1 0
|
||
(and (eq_attr "cpu" "k6") (eq_attr "type" "lea"))
|
||
1 0)
|
||
|
||
|
||
;; "movl MEM,REG / testl REG,REG" is faster on a 486 than "cmpl $0,MEM".
|
||
;; But restricting MEM here would mean that gcc could not remove a redundant
|
||
;; test in cases like "incl MEM / je TARGET".
|
||
;;
|
||
;; We don't want to allow a constant operand for test insns because
|
||
;; (set (cc0) (const_int foo)) has no mode information. Such insns will
|
||
;; be folded while optimizing anyway.
|
||
|
||
;; All test insns have expanders that save the operands away without
|
||
;; actually generating RTL. The bCOND or sCOND (emitted immediately
|
||
;; after the tstM or cmp) will actually emit the tstM or cmpM.
|
||
|
||
;; Processor type -- this attribute must exactly match the processor_type
|
||
;; enumeration in i386.h.
|
||
|
||
(define_attr "cpu" "i386,i486,pentium,pentiumpro,k6"
|
||
(const (symbol_ref "ix86_cpu")))
|
||
|
||
(define_insn "tstsi_1"
|
||
[(set (cc0)
|
||
(match_operand:SI 0 "nonimmediate_operand" "rm"))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[0]))
|
||
return AS2 (test%L0,%0,%0);
|
||
|
||
operands[1] = const0_rtx;
|
||
return AS2 (cmp%L0,%1,%0);
|
||
}"
|
||
[(set_attr "type" "test")])
|
||
|
||
(define_expand "tstsi"
|
||
[(set (cc0)
|
||
(match_operand:SI 0 "nonimmediate_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
i386_compare_gen = gen_tstsi_1;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = const0_rtx;
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "tsthi_1"
|
||
[(set (cc0)
|
||
(match_operand:HI 0 "nonimmediate_operand" "rm"))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[0]))
|
||
return AS2 (test%W0,%0,%0);
|
||
|
||
operands[1] = const0_rtx;
|
||
return AS2 (cmp%W0,%1,%0);
|
||
}"
|
||
[(set_attr "type" "test")])
|
||
|
||
(define_expand "tsthi"
|
||
[(set (cc0)
|
||
(match_operand:HI 0 "nonimmediate_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
i386_compare_gen = gen_tsthi_1;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = const0_rtx;
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "tstqi_1"
|
||
[(set (cc0)
|
||
(match_operand:QI 0 "nonimmediate_operand" "qm"))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[0]))
|
||
return AS2 (test%B0,%0,%0);
|
||
|
||
operands[1] = const0_rtx;
|
||
return AS2 (cmp%B0,%1,%0);
|
||
}"
|
||
[(set_attr "type" "test")])
|
||
|
||
(define_expand "tstqi"
|
||
[(set (cc0)
|
||
(match_operand:QI 0 "nonimmediate_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
i386_compare_gen = gen_tstqi_1;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = const0_rtx;
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "tstsf_cc"
|
||
[(set (cc0)
|
||
(match_operand:SF 0 "register_operand" "f"))
|
||
(clobber (match_scratch:HI 1 "=a"))]
|
||
"TARGET_80387 && ! TARGET_IEEE_FP"
|
||
"*
|
||
{
|
||
if (! STACK_TOP_P (operands[0]))
|
||
abort ();
|
||
|
||
output_asm_insn (\"ftst\", operands);
|
||
|
||
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
|
||
output_asm_insn (AS1 (fstp,%y0), operands);
|
||
|
||
return output_fp_cc0_set (insn);
|
||
}"
|
||
[(set_attr "type" "test")])
|
||
|
||
;; Don't generate tstsf if generating IEEE code, since the `ftst' opcode
|
||
;; isn't IEEE compliant.
|
||
|
||
(define_expand "tstsf"
|
||
[(parallel [(set (cc0)
|
||
(match_operand:SF 0 "register_operand" ""))
|
||
(clobber (match_scratch:HI 1 ""))])]
|
||
"TARGET_80387 && ! TARGET_IEEE_FP"
|
||
"
|
||
{
|
||
i386_compare_gen = gen_tstsf_cc;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = const0_rtx;
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "tstdf_cc"
|
||
[(set (cc0)
|
||
(match_operand:DF 0 "register_operand" "f"))
|
||
(clobber (match_scratch:HI 1 "=a"))]
|
||
"TARGET_80387 && ! TARGET_IEEE_FP"
|
||
"*
|
||
{
|
||
if (! STACK_TOP_P (operands[0]))
|
||
abort ();
|
||
|
||
output_asm_insn (\"ftst\", operands);
|
||
|
||
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
|
||
output_asm_insn (AS1 (fstp,%y0), operands);
|
||
|
||
return output_fp_cc0_set (insn);
|
||
}"
|
||
[(set_attr "type" "test")])
|
||
|
||
;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode
|
||
;; isn't IEEE compliant.
|
||
|
||
(define_expand "tstdf"
|
||
[(parallel [(set (cc0)
|
||
(match_operand:DF 0 "register_operand" ""))
|
||
(clobber (match_scratch:HI 1 ""))])]
|
||
"TARGET_80387 && ! TARGET_IEEE_FP"
|
||
"
|
||
{
|
||
i386_compare_gen = gen_tstdf_cc;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = const0_rtx;
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "tstxf_cc"
|
||
[(set (cc0)
|
||
(match_operand:XF 0 "register_operand" "f"))
|
||
(clobber (match_scratch:HI 1 "=a"))]
|
||
"TARGET_80387 && ! TARGET_IEEE_FP"
|
||
"*
|
||
{
|
||
if (! STACK_TOP_P (operands[0]))
|
||
abort ();
|
||
|
||
output_asm_insn (\"ftst\", operands);
|
||
|
||
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
|
||
output_asm_insn (AS1 (fstp,%y0), operands);
|
||
|
||
return output_fp_cc0_set (insn);
|
||
}"
|
||
[(set_attr "type" "test")])
|
||
|
||
;; Don't generate tstxf if generating IEEE code, since the `ftst' opcode
|
||
;; isn't IEEE compliant.
|
||
|
||
(define_expand "tstxf"
|
||
[(parallel [(set (cc0)
|
||
(match_operand:XF 0 "register_operand" ""))
|
||
(clobber (match_scratch:HI 1 ""))])]
|
||
"TARGET_80387 && ! TARGET_IEEE_FP"
|
||
"
|
||
{
|
||
i386_compare_gen = gen_tstxf_cc;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = const0_rtx;
|
||
DONE;
|
||
}")
|
||
|
||
;;- compare instructions. See comments above tstM patterns about
|
||
;; expansion of these insns.
|
||
|
||
(define_insn "cmpsi_1"
|
||
[(set (cc0)
|
||
(compare (match_operand:SI 0 "nonimmediate_operand" "mr,r")
|
||
(match_operand:SI 1 "general_operand" "ri,mr")))]
|
||
"GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
|
||
"* return AS2 (cmp%L0,%1,%0);"
|
||
[(set_attr "type" "compare")])
|
||
|
||
(define_expand "cmpsi"
|
||
[(set (cc0)
|
||
(compare (match_operand:SI 0 "nonimmediate_operand" "")
|
||
(match_operand:SI 1 "general_operand" "")))]
|
||
""
|
||
"
|
||
{
|
||
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
|
||
operands[0] = force_reg (SImode, operands[0]);
|
||
|
||
i386_compare_gen = gen_cmpsi_1;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = operands[1];
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "cmphi_1"
|
||
[(set (cc0)
|
||
(compare (match_operand:HI 0 "nonimmediate_operand" "mr,r")
|
||
(match_operand:HI 1 "general_operand" "ri,mr")))]
|
||
"GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
|
||
"* return AS2 (cmp%W0,%1,%0);"
|
||
[(set_attr "type" "compare")])
|
||
|
||
(define_expand "cmphi"
|
||
[(set (cc0)
|
||
(compare (match_operand:HI 0 "nonimmediate_operand" "")
|
||
(match_operand:HI 1 "general_operand" "")))]
|
||
""
|
||
"
|
||
{
|
||
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
|
||
operands[0] = force_reg (HImode, operands[0]);
|
||
|
||
i386_compare_gen = gen_cmphi_1;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = operands[1];
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "cmpqi_1"
|
||
[(set (cc0)
|
||
(compare (match_operand:QI 0 "nonimmediate_operand" "q,mq")
|
||
(match_operand:QI 1 "general_operand" "qm,nq")))]
|
||
"GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
|
||
"* return AS2 (cmp%B0,%1,%0);"
|
||
[(set_attr "type" "compare")])
|
||
|
||
(define_expand "cmpqi"
|
||
[(set (cc0)
|
||
(compare (match_operand:QI 0 "nonimmediate_operand" "")
|
||
(match_operand:QI 1 "general_operand" "")))]
|
||
""
|
||
"
|
||
{
|
||
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
|
||
operands[0] = force_reg (QImode, operands[0]);
|
||
|
||
i386_compare_gen = gen_cmpqi_1;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = operands[1];
|
||
DONE;
|
||
}")
|
||
|
||
;; These implement float point compares. For each of DFmode and
|
||
;; SFmode, there is the normal insn, and an insn where the second operand
|
||
;; is converted to the desired mode.
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(match_operator 2 "VOIDmode_compare_op"
|
||
[(match_operand:XF 0 "register_operand" "f")
|
||
(match_operand:XF 1 "register_operand" "f")]))
|
||
(clobber (match_scratch:HI 3 "=a"))]
|
||
"TARGET_80387"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(match_operator 2 "VOIDmode_compare_op"
|
||
[(match_operand:XF 0 "register_operand" "f")
|
||
(float_extend:XF
|
||
(match_operand:DF 1 "nonimmediate_operand" "fm"))]))
|
||
(clobber (match_scratch:HI 3 "=a"))]
|
||
"TARGET_80387"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(match_operator 2 "VOIDmode_compare_op"
|
||
[(float_extend:XF
|
||
(match_operand:DF 0 "nonimmediate_operand" "fm"))
|
||
(match_operand:XF 1 "register_operand" "f")]))
|
||
(clobber (match_scratch:HI 3 "=a"))]
|
||
"TARGET_80387"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(match_operator 2 "VOIDmode_compare_op"
|
||
[(match_operand:XF 0 "register_operand" "f")
|
||
(float_extend:XF
|
||
(match_operand:SF 1 "nonimmediate_operand" "fm"))]))
|
||
(clobber (match_scratch:HI 3 "=a"))]
|
||
"TARGET_80387"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(match_operator 2 "VOIDmode_compare_op"
|
||
[(float_extend:XF
|
||
(match_operand:SF 0 "nonimmediate_operand" "fm"))
|
||
(match_operand:XF 1 "register_operand" "f")]))
|
||
(clobber (match_scratch:HI 3 "=a"))]
|
||
"TARGET_80387"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(compare:CCFPEQ (match_operand:XF 0 "register_operand" "f")
|
||
(match_operand:XF 1 "register_operand" "f")))
|
||
(clobber (match_scratch:HI 2 "=a"))]
|
||
"TARGET_80387"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(match_operator 2 "VOIDmode_compare_op"
|
||
[(match_operand:DF 0 "nonimmediate_operand" "f,fm")
|
||
(match_operand:DF 1 "nonimmediate_operand" "fm,f")]))
|
||
(clobber (match_scratch:HI 3 "=a,a"))]
|
||
"TARGET_80387
|
||
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(match_operator 2 "VOIDmode_compare_op"
|
||
[(match_operand:DF 0 "register_operand" "f")
|
||
(float_extend:DF
|
||
(match_operand:SF 1 "nonimmediate_operand" "fm"))]))
|
||
(clobber (match_scratch:HI 3 "=a"))]
|
||
"TARGET_80387"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(match_operator 2 "VOIDmode_compare_op"
|
||
[(float_extend:DF
|
||
(match_operand:SF 0 "nonimmediate_operand" "fm"))
|
||
(match_operand:DF 1 "register_operand" "f")]))
|
||
(clobber (match_scratch:HI 3 "=a"))]
|
||
"TARGET_80387"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(match_operator 2 "VOIDmode_compare_op"
|
||
[(float_extend:DF
|
||
(match_operand:SF 0 "register_operand" "f"))
|
||
(match_operand:DF 1 "nonimmediate_operand" "fm")]))
|
||
(clobber (match_scratch:HI 3 "=a"))]
|
||
"TARGET_80387"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(compare:CCFPEQ (match_operand:DF 0 "register_operand" "f")
|
||
(match_operand:DF 1 "register_operand" "f")))
|
||
(clobber (match_scratch:HI 2 "=a"))]
|
||
"TARGET_80387"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
;; These two insns will never be generated by combine due to the mode of
|
||
;; the COMPARE.
|
||
;(define_insn ""
|
||
; [(set (cc0)
|
||
; (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f")
|
||
; (float_extend:DF
|
||
; (match_operand:SF 1 "register_operand" "f"))))
|
||
; (clobber (match_scratch:HI 2 "=a"))]
|
||
; "TARGET_80387"
|
||
; "* return output_float_compare (insn, operands);")
|
||
;
|
||
;(define_insn ""
|
||
; [(set (cc0)
|
||
; (compare:CCFPEQ (float_extend:DF
|
||
; (match_operand:SF 0 "register_operand" "f"))
|
||
; (match_operand:DF 1 "register_operand" "f")))
|
||
; (clobber (match_scratch:HI 2 "=a"))]
|
||
; "TARGET_80387"
|
||
; "* return output_float_compare (insn, operands);")
|
||
|
||
(define_insn "*cmpsf_cc_1"
|
||
[(set (cc0)
|
||
(match_operator 2 "VOIDmode_compare_op"
|
||
[(match_operand:SF 0 "nonimmediate_operand" "f,fm")
|
||
(match_operand:SF 1 "nonimmediate_operand" "fm,f")]))
|
||
(clobber (match_scratch:HI 3 "=a,a"))]
|
||
"TARGET_80387
|
||
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(compare:CCFPEQ (match_operand:SF 0 "register_operand" "f")
|
||
(match_operand:SF 1 "register_operand" "f")))
|
||
(clobber (match_scratch:HI 2 "=a"))]
|
||
"TARGET_80387"
|
||
"* return output_float_compare (insn, operands);"
|
||
[(set_attr "type" "fcompare")])
|
||
|
||
(define_expand "cmpxf"
|
||
[(set (cc0)
|
||
(compare (match_operand:XF 0 "register_operand" "")
|
||
(match_operand:XF 1 "register_operand" "")))]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
i386_compare_gen = gen_cmpxf_cc;
|
||
i386_compare_gen_eq = gen_cmpxf_ccfpeq;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = operands[1];
|
||
DONE;
|
||
}")
|
||
|
||
(define_expand "cmpdf"
|
||
[(set (cc0)
|
||
(compare (match_operand:DF 0 "register_operand" "")
|
||
(match_operand:DF 1 "general_operand" "")))]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
i386_compare_gen = gen_cmpdf_cc;
|
||
i386_compare_gen_eq = gen_cmpdf_ccfpeq;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = (immediate_operand (operands[1], DFmode))
|
||
? copy_to_mode_reg (DFmode, operands[1]) : operands[1];
|
||
DONE;
|
||
}")
|
||
|
||
(define_expand "cmpsf"
|
||
[(set (cc0)
|
||
(compare (match_operand:SF 0 "register_operand" "")
|
||
(match_operand:SF 1 "general_operand" "")))]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
i386_compare_gen = gen_cmpsf_cc;
|
||
i386_compare_gen_eq = gen_cmpsf_ccfpeq;
|
||
i386_compare_op0 = operands[0];
|
||
i386_compare_op1 = (immediate_operand (operands[1], SFmode))
|
||
? copy_to_mode_reg (SFmode, operands[1]) : operands[1];
|
||
DONE;
|
||
}")
|
||
|
||
(define_expand "cmpxf_cc"
|
||
[(parallel [(set (cc0)
|
||
(compare (match_operand:XF 0 "register_operand" "")
|
||
(match_operand:XF 1 "register_operand" "")))
|
||
(clobber (match_scratch:HI 2 ""))])]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "cmpxf_ccfpeq"
|
||
[(parallel [(set (cc0)
|
||
(compare:CCFPEQ (match_operand:XF 0 "register_operand" "")
|
||
(match_operand:XF 1 "register_operand" "")))
|
||
(clobber (match_scratch:HI 2 ""))])]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "cmpdf_cc"
|
||
[(parallel [(set (cc0)
|
||
(compare (match_operand:DF 0 "register_operand" "")
|
||
(match_operand:DF 1 "register_operand" "")))
|
||
(clobber (match_scratch:HI 2 ""))])]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "cmpdf_ccfpeq"
|
||
[(parallel [(set (cc0)
|
||
(compare:CCFPEQ (match_operand:DF 0 "register_operand" "")
|
||
(match_operand:DF 1 "register_operand" "")))
|
||
(clobber (match_scratch:HI 2 ""))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
if (! register_operand (operands[1], DFmode))
|
||
operands[1] = copy_to_mode_reg (DFmode, operands[1]);
|
||
}")
|
||
|
||
(define_expand "cmpsf_cc"
|
||
[(parallel [(set (cc0)
|
||
(compare (match_operand:SF 0 "register_operand" "")
|
||
(match_operand:SF 1 "register_operand" "")))
|
||
(clobber (match_scratch:HI 2 ""))])]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "cmpsf_ccfpeq"
|
||
[(parallel [(set (cc0)
|
||
(compare:CCFPEQ (match_operand:SF 0 "register_operand" "")
|
||
(match_operand:SF 1 "register_operand" "")))
|
||
(clobber (match_scratch:HI 2 ""))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
if (! register_operand (operands[1], SFmode))
|
||
operands[1] = copy_to_mode_reg (SFmode, operands[1]);
|
||
}")
|
||
|
||
;; logical compare
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(and:SI (match_operand:SI 0 "general_operand" "%ro")
|
||
(match_operand:SI 1 "nonmemory_operand" "ri")))]
|
||
""
|
||
"*
|
||
{
|
||
/* For small integers, we may actually use testb. */
|
||
if (GET_CODE (operands[1]) == CONST_INT
|
||
&& ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
|
||
&& (! REG_P (operands[0]) || QI_REG_P (operands[0]))
|
||
/* A Pentium test is pairable only with eax. Not with ah or al. */
|
||
&& (! REG_P (operands[0]) || REGNO (operands[0]) || !TARGET_PENTIUM
|
||
|| optimize_size))
|
||
{
|
||
/* We may set the sign bit spuriously. */
|
||
|
||
if ((INTVAL (operands[1]) & ~0xff) == 0)
|
||
{
|
||
cc_status.flags |= CC_NOT_NEGATIVE;
|
||
return AS2 (test%B0,%1,%b0);
|
||
}
|
||
|
||
if ((INTVAL (operands[1]) & ~0xff00) == 0)
|
||
{
|
||
cc_status.flags |= CC_NOT_NEGATIVE;
|
||
operands[1] = GEN_INT (INTVAL (operands[1]) >> 8);
|
||
|
||
if (QI_REG_P (operands[0]))
|
||
return AS2 (test%B0,%1,%h0);
|
||
else
|
||
{
|
||
operands[0] = adj_offsettable_operand (operands[0], 1);
|
||
return AS2 (test%B0,%1,%b0);
|
||
}
|
||
}
|
||
|
||
if (GET_CODE (operands[0]) == MEM
|
||
&& (INTVAL (operands[1]) & ~0xff0000) == 0)
|
||
{
|
||
cc_status.flags |= CC_NOT_NEGATIVE;
|
||
operands[1] = GEN_INT (INTVAL (operands[1]) >> 16);
|
||
operands[0] = adj_offsettable_operand (operands[0], 2);
|
||
return AS2 (test%B0,%1,%b0);
|
||
}
|
||
|
||
if (GET_CODE (operands[0]) == MEM
|
||
&& (INTVAL (operands[1]) & ~0xff000000) == 0)
|
||
{
|
||
operands[1] = GEN_INT ((INTVAL (operands[1]) >> 24) & 0xff);
|
||
operands[0] = adj_offsettable_operand (operands[0], 3);
|
||
return AS2 (test%B0,%1,%b0);
|
||
}
|
||
}
|
||
|
||
if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
|
||
return AS2 (test%L0,%1,%0);
|
||
|
||
return AS2 (test%L1,%0,%1);
|
||
}"
|
||
[(set_attr "type" "compare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(and:HI (match_operand:HI 0 "general_operand" "%ro")
|
||
(match_operand:HI 1 "nonmemory_operand" "ri")))]
|
||
""
|
||
"*
|
||
{
|
||
if (GET_CODE (operands[1]) == CONST_INT
|
||
&& ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
|
||
&& (! REG_P (operands[0]) || QI_REG_P (operands[0])))
|
||
{
|
||
if ((INTVAL (operands[1]) & 0xff00) == 0)
|
||
{
|
||
/* ??? This might not be necessary. */
|
||
if (INTVAL (operands[1]) & 0xffff0000)
|
||
operands[1] = GEN_INT (INTVAL (operands[1]) & 0xff);
|
||
|
||
/* We may set the sign bit spuriously. */
|
||
cc_status.flags |= CC_NOT_NEGATIVE;
|
||
return AS2 (test%B0,%1,%b0);
|
||
}
|
||
|
||
if ((INTVAL (operands[1]) & 0xff) == 0)
|
||
{
|
||
operands[1] = GEN_INT ((INTVAL (operands[1]) >> 8) & 0xff);
|
||
|
||
if (QI_REG_P (operands[0]))
|
||
return AS2 (test%B0,%1,%h0);
|
||
else
|
||
{
|
||
operands[0] = adj_offsettable_operand (operands[0], 1);
|
||
return AS2 (test%B0,%1,%b0);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* use 32-bit test instruction if there are no sign issues */
|
||
if (GET_CODE (operands[1]) == CONST_INT
|
||
&& !(INTVAL (operands[1]) & ~0x7fff)
|
||
&& i386_aligned_p (operands[0]))
|
||
return AS2 (test%L0,%1,%k0);
|
||
|
||
if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
|
||
return AS2 (test%W0,%1,%0);
|
||
|
||
return AS2 (test%W1,%0,%1);
|
||
}"
|
||
[(set_attr "type" "compare")])
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(and:QI (match_operand:QI 0 "nonimmediate_operand" "%qm")
|
||
(match_operand:QI 1 "nonmemory_operand" "qi")))]
|
||
""
|
||
"*
|
||
{
|
||
if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
|
||
return AS2 (test%B0,%1,%0);
|
||
|
||
return AS2 (test%B1,%0,%1);
|
||
}"
|
||
[(set_attr "type" "compare")])
|
||
|
||
;; move instructions.
|
||
;; There is one for each machine mode,
|
||
;; and each is preceded by a corresponding push-insn pattern
|
||
;; (since pushes are not general_operands on the 386).
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "push_operand" "=<")
|
||
(match_operand:SI 1 "nonmemory_operand" "rn"))]
|
||
"flag_pic"
|
||
"* return AS1 (push%L0,%1);"
|
||
[(set_attr "memory" "store")])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "push_operand" "=<")
|
||
(match_operand:SI 1 "nonmemory_operand" "ri"))]
|
||
"!flag_pic"
|
||
"* return AS1 (push%L0,%1);"
|
||
[(set_attr "memory" "store")])
|
||
|
||
;; On a 386, it is faster to push MEM directly.
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "push_operand" "=<")
|
||
(match_operand:SI 1 "memory_operand" "m"))]
|
||
"TARGET_PUSH_MEMORY"
|
||
"* return AS1 (push%L0,%1);"
|
||
[(set_attr "type" "memory")
|
||
(set_attr "memory" "load")])
|
||
|
||
;; General case of fullword move.
|
||
|
||
;; If generating PIC code and operands[1] is a symbolic CONST, emit a
|
||
;; move to get the address of the symbolic object from the GOT.
|
||
|
||
(define_expand "movsi"
|
||
[(set (match_operand:SI 0 "general_operand" "")
|
||
(match_operand:SI 1 "general_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
extern int flag_pic;
|
||
|
||
if (flag_pic && SYMBOLIC_CONST (operands[1]))
|
||
emit_pic_move (operands, SImode);
|
||
|
||
/* Don't generate memory->memory moves, go through a register */
|
||
else if (TARGET_MOVE
|
||
&& no_new_pseudos == 0
|
||
&& GET_CODE (operands[0]) == MEM
|
||
&& GET_CODE (operands[1]) == MEM)
|
||
{
|
||
operands[1] = force_reg (SImode, operands[1]);
|
||
}
|
||
}")
|
||
|
||
;; On i486, incl reg is faster than movl $1,reg.
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "general_operand" "=g,r,r")
|
||
(match_operand:SI 1 "general_operand" "rn,i,m"))]
|
||
"((!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
|
||
|| (GET_CODE (operands[1]) != MEM))
|
||
&& flag_pic"
|
||
"*
|
||
{
|
||
rtx link;
|
||
|
||
/* K6: mov reg,0 is slightly faster than xor reg,reg but is 3 bytes
|
||
longer. */
|
||
if ((ix86_cpu != PROCESSOR_K6 || optimize_size)
|
||
&& operands[1] == const0_rtx && REG_P (operands[0]))
|
||
return AS2 (xor%L0,%0,%0);
|
||
|
||
if (operands[1] == const1_rtx
|
||
/* PPRO and K6 prefer mov to inc to reduce dependencies. */
|
||
&& (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO)
|
||
&& (link = find_reg_note (insn, REG_WAS_0, 0))
|
||
/* Make sure the insn that stored the 0 is still present. */
|
||
&& ! INSN_DELETED_P (XEXP (link, 0))
|
||
&& GET_CODE (XEXP (link, 0)) != NOTE
|
||
/* Make sure cross jumping didn't happen here. */
|
||
&& no_labels_between_p (XEXP (link, 0), insn)
|
||
/* Make sure the reg hasn't been clobbered. */
|
||
&& ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
|
||
/* Fastest way to change a 0 to a 1. */
|
||
return AS1 (inc%L0,%0);
|
||
|
||
if (SYMBOLIC_CONST (operands[1]))
|
||
return AS2 (lea%L0,%a1,%0);
|
||
|
||
return AS2 (mov%L0,%1,%0);
|
||
}"
|
||
[(set_attr "type" "integer,integer,memory")
|
||
(set_attr "memory" "*,*,load")])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "general_operand" "=g,r")
|
||
(match_operand:SI 1 "general_operand" "ri,m"))]
|
||
"((!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
|
||
|| (GET_CODE (operands[1]) != MEM))
|
||
&& !flag_pic"
|
||
"*
|
||
{
|
||
rtx link;
|
||
|
||
/* Use of xor was disabled for AMD K6 as recommended by the Optimization
|
||
Manual. My test shows, that this generally hurts the performance, because
|
||
mov is longer and takes longer to decode and decoding is the main
|
||
bottleneck of K6 when executing GCC code. */
|
||
|
||
if (operands[1] == const0_rtx && REG_P (operands[0]))
|
||
return AS2 (xor%L0,%0,%0);
|
||
|
||
if (operands[1] == const1_rtx
|
||
/* PPRO and K6 prefer mov to inc to reduce dependencies. */
|
||
&& (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO)
|
||
&& (link = find_reg_note (insn, REG_WAS_0, 0))
|
||
/* Make sure the insn that stored the 0 is still present. */
|
||
&& ! INSN_DELETED_P (XEXP (link, 0))
|
||
&& GET_CODE (XEXP (link, 0)) != NOTE
|
||
/* Make sure cross jumping didn't happen here. */
|
||
&& no_labels_between_p (XEXP (link, 0), insn)
|
||
/* Make sure the reg hasn't been clobbered. */
|
||
&& ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
|
||
/* Fastest way to change a 0 to a 1. */
|
||
return AS1 (inc%L0,%0);
|
||
|
||
return AS2 (mov%L0,%1,%0);
|
||
}"
|
||
[(set_attr "type" "integer,memory")
|
||
(set_attr "memory" "*,load")])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "push_operand" "=<")
|
||
(match_operand:HI 1 "nonmemory_operand" "ri"))]
|
||
""
|
||
"* return AS1 (push%W0,%1);"
|
||
[(set_attr "type" "memory")
|
||
(set_attr "memory" "store")])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "push_operand" "=<")
|
||
(match_operand:HI 1 "memory_operand" "m"))]
|
||
"TARGET_PUSH_MEMORY"
|
||
"* return AS1 (push%W0,%1);"
|
||
[(set_attr "type" "memory")
|
||
(set_attr "memory" "load")])
|
||
|
||
;; On i486, an incl and movl are both faster than incw and movw.
|
||
|
||
(define_expand "movhi"
|
||
[(set (match_operand:HI 0 "general_operand" "")
|
||
(match_operand:HI 1 "general_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
/* Don't generate memory->memory moves, go through a register */
|
||
if (TARGET_MOVE
|
||
&& no_new_pseudos == 0
|
||
&& GET_CODE (operands[0]) == MEM
|
||
&& GET_CODE (operands[1]) == MEM)
|
||
{
|
||
operands[1] = force_reg (HImode, operands[1]);
|
||
}
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "general_operand" "=g,r")
|
||
(match_operand:HI 1 "general_operand" "ri,m"))]
|
||
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
rtx link;
|
||
if (REG_P (operands[0]) && operands[1] == const0_rtx)
|
||
return AS2 (xor%L0,%k0,%k0);
|
||
|
||
if (REG_P (operands[0]) && operands[1] == const1_rtx
|
||
/* PPRO and K6 prefer mov to inc to reduce dependencies. */
|
||
&& (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO)
|
||
&& (link = find_reg_note (insn, REG_WAS_0, 0))
|
||
/* Make sure the insn that stored the 0 is still present. */
|
||
&& ! INSN_DELETED_P (XEXP (link, 0))
|
||
&& GET_CODE (XEXP (link, 0)) != NOTE
|
||
/* Make sure cross jumping didn't happen here. */
|
||
&& no_labels_between_p (XEXP (link, 0), insn)
|
||
/* Make sure the reg hasn't been clobbered. */
|
||
&& ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
|
||
/* Fastest way to change a 0 to a 1. */
|
||
return AS1 (inc%L0,%k0);
|
||
|
||
if (REG_P (operands[0]))
|
||
{
|
||
if (i386_aligned_p (operands[1]))
|
||
{
|
||
operands[1] = i386_sext16_if_const (operands[1]);
|
||
return AS2 (mov%L0,%k1,%k0);
|
||
}
|
||
if (! TARGET_ZERO_EXTEND_WITH_AND)
|
||
{
|
||
/* movzwl is faster than movw on the Pentium Pro,
|
||
* although not as fast as an aligned movl. */
|
||
#ifdef INTEL_SYNTAX
|
||
return AS2 (movzx,%1,%k0);
|
||
#else
|
||
return AS2 (movz%W0%L0,%1,%k0);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
return AS2 (mov%W0,%1,%0);
|
||
}"
|
||
[(set_attr "type" "integer,memory")
|
||
(set_attr "memory" "*,load")])
|
||
|
||
(define_expand "movstricthi"
|
||
[(set (strict_low_part (match_operand:HI 0 "general_operand" ""))
|
||
(match_operand:HI 1 "general_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
/* Don't generate memory->memory moves, go through a register */
|
||
if (TARGET_MOVE
|
||
&& no_new_pseudos == 0
|
||
&& GET_CODE (operands[0]) == MEM
|
||
&& GET_CODE (operands[1]) == MEM)
|
||
{
|
||
operands[1] = force_reg (HImode, operands[1]);
|
||
}
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (strict_low_part (match_operand:HI 0 "general_operand" "+g,r"))
|
||
(match_operand:HI 1 "general_operand" "ri,m"))]
|
||
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
rtx link;
|
||
|
||
/* Use of xor was disabled for AMD K6 as recommended by the Optimization
|
||
Manual. My test shows, that this generally hurts the performance, because
|
||
mov is longer and takes longer to decode and decoding is the main
|
||
bottleneck of K6 when executing GCC code. */
|
||
|
||
if (operands[1] == const0_rtx && REG_P (operands[0]))
|
||
return AS2 (xor%W0,%0,%0);
|
||
|
||
if (operands[1] == const1_rtx
|
||
/* PPRO and K6 prefer mov to inc to reduce dependencies. */
|
||
&& (optimize_size || (int)ix86_cpu < (int)PROCESSOR_PENTIUMPRO)
|
||
&& (link = find_reg_note (insn, REG_WAS_0, 0))
|
||
/* Make sure the insn that stored the 0 is still present. */
|
||
&& ! INSN_DELETED_P (XEXP (link, 0))
|
||
&& GET_CODE (XEXP (link, 0)) != NOTE
|
||
/* Make sure cross jumping didn't happen here. */
|
||
&& no_labels_between_p (XEXP (link, 0), insn)
|
||
/* Make sure the reg hasn't been clobbered. */
|
||
&& ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
|
||
/* Fastest way to change a 0 to a 1. */
|
||
return AS1 (inc%W0,%0);
|
||
|
||
return AS2 (mov%W0,%1,%0);
|
||
}"
|
||
[(set_attr "type" "integer,memory")])
|
||
|
||
;; emit_push_insn when it calls move_by_pieces
|
||
;; requires an insn to "push a byte".
|
||
;; But actually we use pushw, which has the effect of rounding
|
||
;; the amount pushed up to a halfword.
|
||
(define_insn ""
|
||
[(set (match_operand:QI 0 "push_operand" "=<")
|
||
(match_operand:QI 1 "const_int_operand" "n"))]
|
||
""
|
||
"* return AS1(push%W0,%1);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:QI 0 "push_operand" "=<")
|
||
(match_operand:QI 1 "register_operand" "q"))]
|
||
""
|
||
"*
|
||
{
|
||
operands[1] = gen_rtx_REG (HImode, REGNO (operands[1]));
|
||
return AS1 (push%W0,%1);
|
||
}")
|
||
|
||
;; On i486, incb reg is faster than movb $1,reg.
|
||
|
||
;; ??? Do a recognizer for zero_extract that looks just like this, but reads
|
||
;; or writes %ah, %bh, %ch, %dh.
|
||
|
||
(define_expand "movqi"
|
||
[(set (match_operand:QI 0 "general_operand" "")
|
||
(match_operand:QI 1 "general_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
/* Don't generate memory->memory moves, go through a register */
|
||
if (TARGET_MOVE
|
||
&& no_new_pseudos == 0
|
||
&& GET_CODE (operands[0]) == MEM
|
||
&& GET_CODE (operands[1]) == MEM)
|
||
{
|
||
operands[1] = force_reg (QImode, operands[1]);
|
||
}
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=q,*r,qm")
|
||
(match_operand:QI 1 "general_operand" "*g,*rn,qn"))]
|
||
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
rtx link;
|
||
|
||
/* movb $0,reg8 is 2 bytes, the same as xorl reg8,reg8.
|
||
It is at least as fast as xor on any processor except a Pentium. */
|
||
|
||
if (operands[1] == const1_rtx
|
||
&& TARGET_PENTIUM
|
||
&& (link = find_reg_note (insn, REG_WAS_0, 0))
|
||
/* Make sure the insn that stored the 0 is still present. */
|
||
&& ! INSN_DELETED_P (XEXP (link, 0))
|
||
&& GET_CODE (XEXP (link, 0)) != NOTE
|
||
/* Make sure cross jumping didn't happen here. */
|
||
&& no_labels_between_p (XEXP (link, 0), insn)
|
||
/* Make sure the reg hasn't been clobbered. */
|
||
&& ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
|
||
{
|
||
/* Fastest way to change a 0 to a 1.
|
||
If inc%B0 isn't allowed, use inc%L0. */
|
||
if (NON_QI_REG_P (operands[0]))
|
||
return AS1 (inc%L0,%k0);
|
||
else
|
||
return AS1 (inc%B0,%0);
|
||
}
|
||
|
||
/* If mov%B0 isn't allowed for one of these regs, use mov%L0. */
|
||
if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1]))
|
||
return (AS2 (mov%L0,%k1,%k0));
|
||
|
||
return (AS2 (mov%B0,%1,%0));
|
||
}")
|
||
|
||
;; If it becomes necessary to support movstrictqi into %esi or %edi,
|
||
;; use the insn sequence:
|
||
;;
|
||
;; shrdl $8,srcreg,dstreg
|
||
;; rorl $24,dstreg
|
||
;;
|
||
;; If operands[1] is a constant, then an andl/orl sequence would be
|
||
;; faster.
|
||
|
||
(define_expand "movstrictqi"
|
||
[(set (strict_low_part (match_operand:QI 0 "general_operand" ""))
|
||
(match_operand:QI 1 "general_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
/* Don't generate memory->memory moves, go through a register */
|
||
if (TARGET_MOVE
|
||
&& no_new_pseudos == 0
|
||
&& GET_CODE (operands[0]) == MEM
|
||
&& GET_CODE (operands[1]) == MEM)
|
||
{
|
||
operands[1] = force_reg (QImode, operands[1]);
|
||
}
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q"))
|
||
(match_operand:QI 1 "general_operand" "*qn,m"))]
|
||
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
rtx link;
|
||
|
||
/* movb $0,reg8 is 2 bytes, the same as xorl reg8,reg8. */
|
||
|
||
if (operands[1] == const1_rtx
|
||
&& TARGET_PENTIUM
|
||
&& ! NON_QI_REG_P (operands[0])
|
||
&& (link = find_reg_note (insn, REG_WAS_0, 0))
|
||
/* Make sure the insn that stored the 0 is still present. */
|
||
&& ! INSN_DELETED_P (XEXP (link, 0))
|
||
&& GET_CODE (XEXP (link, 0)) != NOTE
|
||
/* Make sure cross jumping didn't happen here. */
|
||
&& no_labels_between_p (XEXP (link, 0), insn)
|
||
/* Make sure the reg hasn't been clobbered. */
|
||
&& ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
|
||
/* Fastest way to change a 0 to a 1. */
|
||
return AS1 (inc%B0,%0);
|
||
|
||
/* If mov%B0 isn't allowed for one of these regs, use mov%L0. */
|
||
if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1]))
|
||
{
|
||
abort ();
|
||
return (AS2 (mov%L0,%k1,%k0));
|
||
}
|
||
|
||
return AS2 (mov%B0,%1,%0);
|
||
}")
|
||
|
||
(define_insn "movsf_push"
|
||
[(set (match_operand:SF 0 "push_operand" "=<,<")
|
||
(match_operand:SF 1 "general_operand" "*rfF,m"))]
|
||
"TARGET_PUSH_MEMORY || GET_CODE (operands[1]) != MEM
|
||
|| reload_in_progress || reload_completed"
|
||
"*
|
||
{
|
||
if (STACK_REG_P (operands[1]))
|
||
{
|
||
rtx xops[3];
|
||
|
||
if (! STACK_TOP_P (operands[1]))
|
||
abort ();
|
||
|
||
xops[0] = AT_SP (SFmode);
|
||
xops[1] = GEN_INT (4);
|
||
xops[2] = stack_pointer_rtx;
|
||
|
||
output_asm_insn (AS2 (sub%L2,%1,%2), xops);
|
||
|
||
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
|
||
output_asm_insn (AS1 (fstp%S0,%0), xops);
|
||
else
|
||
output_asm_insn (AS1 (fst%S0,%0), xops);
|
||
|
||
RET;
|
||
}
|
||
|
||
return AS1 (push%L0,%1);
|
||
}")
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "push_operand" "")
|
||
(match_operand:SF 1 "general_operand" ""))]
|
||
"reload_completed && STACK_REG_P (operands[1])"
|
||
[(set (reg:SI 7)
|
||
(minus:SI (reg:SI 7) (const_int 4)))
|
||
(set (mem:SF (reg:SI 7))
|
||
(match_dup 1))]
|
||
"")
|
||
|
||
(define_expand "movsf"
|
||
[(set (match_operand:SF 0 "general_operand" "")
|
||
(match_operand:SF 1 "general_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
/* Don't generate memory->memory moves, go through a register */
|
||
if (TARGET_MOVE
|
||
&& no_new_pseudos == 0
|
||
&& GET_CODE (operands[0]) == MEM
|
||
&& GET_CODE (operands[1]) == MEM)
|
||
{
|
||
operands[1] = force_reg (SFmode, operands[1]);
|
||
}
|
||
|
||
/* If we are loading a floating point constant that isn't 0 or 1
|
||
into a register, force the value to memory now, since we'll
|
||
get better code out the back end. */
|
||
else if ((reload_in_progress | reload_completed) == 0
|
||
&& GET_CODE (operands[0]) != MEM
|
||
&& GET_CODE (operands[1]) == CONST_DOUBLE
|
||
&& !standard_80387_constant_p (operands[1]))
|
||
{
|
||
operands[1] = validize_mem (force_const_mem (SFmode, operands[1]));
|
||
}
|
||
}")
|
||
|
||
;; For the purposes of regclass, prefer FLOAT_REGS.
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,!*r,!m")
|
||
(match_operand:SF 1 "general_operand" "fmG,f,*rmF,*rF"))]
|
||
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
|
||
|
||
/* First handle a `pop' insn or a `fld %st(0)' */
|
||
|
||
if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]))
|
||
{
|
||
if (stack_top_dies)
|
||
return AS1 (fstp,%y0);
|
||
else
|
||
return AS1 (fld,%y0);
|
||
}
|
||
|
||
/* Handle other kinds of writes from the 387 */
|
||
|
||
if (STACK_TOP_P (operands[1]))
|
||
{
|
||
if (stack_top_dies)
|
||
return AS1 (fstp%z0,%y0);
|
||
else
|
||
return AS1 (fst%z0,%y0);
|
||
}
|
||
|
||
/* Handle other kinds of reads to the 387 */
|
||
|
||
if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
|
||
return output_move_const_single (operands);
|
||
|
||
if (STACK_TOP_P (operands[0]))
|
||
return AS1 (fld%z1,%y1);
|
||
|
||
/* Handle all SFmode moves not involving the 387 */
|
||
|
||
return singlemove_string (operands);
|
||
}"
|
||
[(set_attr "type" "fld")])
|
||
|
||
|
||
(define_insn "swapsf"
|
||
[(set (match_operand:SF 0 "register_operand" "f")
|
||
(match_operand:SF 1 "register_operand" "f"))
|
||
(set (match_dup 1)
|
||
(match_dup 0))]
|
||
""
|
||
"*
|
||
{
|
||
if (STACK_TOP_P (operands[0]))
|
||
return AS1 (fxch,%1);
|
||
else
|
||
return AS1 (fxch,%0);
|
||
}")
|
||
|
||
|
||
(define_insn "movdf_push"
|
||
[(set (match_operand:DF 0 "push_operand" "=<,<")
|
||
(match_operand:DF 1 "general_operand" "*rfF,o"))]
|
||
"TARGET_PUSH_MEMORY || GET_CODE (operands[1]) != MEM
|
||
|| reload_in_progress || reload_completed"
|
||
"*
|
||
{
|
||
if (STACK_REG_P (operands[1]))
|
||
{
|
||
rtx xops[3];
|
||
|
||
xops[0] = AT_SP (DFmode);
|
||
xops[1] = GEN_INT (8);
|
||
xops[2] = stack_pointer_rtx;
|
||
|
||
output_asm_insn (AS2 (sub%L2,%1,%2), xops);
|
||
|
||
if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
|
||
output_asm_insn (AS1 (fstp%Q0,%0), xops);
|
||
else
|
||
output_asm_insn (AS1 (fst%Q0,%0), xops);
|
||
|
||
RET;
|
||
}
|
||
|
||
if (which_alternative == 1)
|
||
return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 0, 0);
|
||
|
||
return output_move_double (operands);
|
||
}")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "push_operand" "")
|
||
(match_operand:DF 1 "register_operand" ""))]
|
||
"reload_completed && STACK_REG_P (operands[1])"
|
||
[(set (reg:SI 7)
|
||
(minus:SI (reg:SI 7) (const_int 8)))
|
||
(set (mem:DF (reg:SI 7))
|
||
(match_dup 1))]
|
||
"")
|
||
|
||
(define_expand "movdf"
|
||
[(set (match_operand:DF 0 "general_operand" "")
|
||
(match_operand:DF 1 "general_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
/* Don't generate memory->memory moves, go through a register */
|
||
if (TARGET_MOVE
|
||
&& no_new_pseudos == 0
|
||
&& GET_CODE (operands[0]) == MEM
|
||
&& GET_CODE (operands[1]) == MEM)
|
||
{
|
||
operands[1] = force_reg (DFmode, operands[1]);
|
||
}
|
||
|
||
/* If we are loading a floating point constant that isn't 0 or 1 into a
|
||
register, indicate we need the pic register loaded. This could be
|
||
optimized into stores of constants if the target eventually moves to
|
||
memory, but better safe than sorry. */
|
||
else if ((reload_in_progress | reload_completed) == 0
|
||
&& GET_CODE (operands[0]) != MEM
|
||
&& GET_CODE (operands[1]) == CONST_DOUBLE
|
||
&& !standard_80387_constant_p (operands[1]))
|
||
{
|
||
operands[1] = validize_mem (force_const_mem (DFmode, operands[1]));
|
||
}
|
||
}")
|
||
|
||
;; For the purposes of regclass, prefer FLOAT_REGS.
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,!*r,!o")
|
||
(match_operand:DF 1 "general_operand" "fmG,f,*roF,*rF"))]
|
||
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
|
||
|| (GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
|
||
|
||
/* First handle a `pop' insn or a `fld %st(0)' */
|
||
|
||
if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]))
|
||
{
|
||
if (stack_top_dies)
|
||
return AS1 (fstp,%y0);
|
||
else
|
||
return AS1 (fld,%y0);
|
||
}
|
||
|
||
/* Handle other kinds of writes from the 387 */
|
||
|
||
if (STACK_TOP_P (operands[1]))
|
||
{
|
||
if (stack_top_dies)
|
||
return AS1 (fstp%z0,%y0);
|
||
else
|
||
return AS1 (fst%z0,%y0);
|
||
}
|
||
|
||
/* Handle other kinds of reads to the 387 */
|
||
|
||
if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
|
||
return output_move_const_single (operands);
|
||
|
||
if (STACK_TOP_P (operands[0]))
|
||
return AS1 (fld%z1,%y1);
|
||
|
||
/* Handle all DFmode moves not involving the 387 */
|
||
|
||
return output_move_double (operands);
|
||
}"
|
||
[(set_attr "type" "fld")])
|
||
|
||
|
||
|
||
(define_insn "swapdf"
|
||
[(set (match_operand:DF 0 "register_operand" "f")
|
||
(match_operand:DF 1 "register_operand" "f"))
|
||
(set (match_dup 1)
|
||
(match_dup 0))]
|
||
""
|
||
"*
|
||
{
|
||
if (STACK_TOP_P (operands[0]))
|
||
return AS1 (fxch,%1);
|
||
else
|
||
return AS1 (fxch,%0);
|
||
}")
|
||
|
||
(define_insn "movxf_push"
|
||
[(set (match_operand:XF 0 "push_operand" "=<,<")
|
||
(match_operand:XF 1 "general_operand" "*rfF,o"))]
|
||
"TARGET_PUSH_MEMORY || GET_CODE (operands[1]) != MEM
|
||
|| reload_in_progress || reload_completed"
|
||
"*
|
||
{
|
||
if (STACK_REG_P (operands[1]))
|
||
{
|
||
rtx xops[3];
|
||
|
||
xops[0] = AT_SP (XFmode);
|
||
xops[1] = GEN_INT (12);
|
||
xops[2] = stack_pointer_rtx;
|
||
|
||
output_asm_insn (AS2 (sub%L2,%1,%2), xops);
|
||
|
||
output_asm_insn (AS1 (fstp%T0,%0), xops);
|
||
if (! find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
|
||
output_asm_insn (AS1 (fld%T0,%0), xops);
|
||
|
||
RET;
|
||
}
|
||
|
||
if (which_alternative == 1)
|
||
return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 0, 0);
|
||
|
||
return output_move_double (operands);
|
||
}")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "push_operand" "")
|
||
(match_operand:XF 1 "register_operand" ""))]
|
||
"reload_completed && STACK_REG_P (operands[1])"
|
||
[(set (reg:SI 7)
|
||
(minus:SI (reg:SI 7) (const_int 12)))
|
||
(set (mem:XF (reg:SI 7))
|
||
(match_dup 1))]
|
||
"")
|
||
|
||
(define_expand "movxf"
|
||
[(set (match_operand:XF 0 "general_operand" "")
|
||
(match_operand:XF 1 "general_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
/* Don't generate memory->memory moves, go through a register */
|
||
if (TARGET_MOVE
|
||
&& no_new_pseudos == 0
|
||
&& GET_CODE (operands[0]) == MEM
|
||
&& GET_CODE (operands[1]) == MEM)
|
||
{
|
||
operands[1] = force_reg (XFmode, operands[1]);
|
||
}
|
||
|
||
/* If we are loading a floating point constant that isn't 0 or 1
|
||
into a register, indicate we need the pic register loaded. This could
|
||
be optimized into stores of constants if the target eventually moves
|
||
to memory, but better safe than sorry. */
|
||
else if ((reload_in_progress | reload_completed) == 0
|
||
&& GET_CODE (operands[0]) != MEM
|
||
&& GET_CODE (operands[1]) == CONST_DOUBLE
|
||
&& !standard_80387_constant_p (operands[1]))
|
||
{
|
||
operands[1] = validize_mem (force_const_mem (XFmode, operands[1]));
|
||
}
|
||
}")
|
||
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,!*r,!o")
|
||
(match_operand:XF 1 "general_operand" "fmG,f,*roF,*rF"))]
|
||
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
|
||
|| (GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
|
||
|
||
/* First handle a `pop' insn or a `fld %st(0)' */
|
||
|
||
if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]))
|
||
{
|
||
if (stack_top_dies)
|
||
return AS1 (fstp,%y0);
|
||
else
|
||
return AS1 (fld,%y0);
|
||
}
|
||
|
||
/* Handle other kinds of writes from the 387 */
|
||
|
||
if (STACK_TOP_P (operands[1]))
|
||
{
|
||
output_asm_insn (AS1 (fstp%z0,%y0), operands);
|
||
if (! stack_top_dies)
|
||
return AS1 (fld%z0,%y0);
|
||
|
||
RET;
|
||
}
|
||
|
||
/* Handle other kinds of reads to the 387 */
|
||
|
||
if (STACK_TOP_P (operands[0]) && GET_CODE (operands[1]) == CONST_DOUBLE)
|
||
return output_move_const_single (operands);
|
||
|
||
if (STACK_TOP_P (operands[0]))
|
||
return AS1 (fld%z1,%y1);
|
||
|
||
/* Handle all XFmode moves not involving the 387 */
|
||
|
||
return output_move_double (operands);
|
||
}")
|
||
|
||
(define_insn "swapxf"
|
||
[(set (match_operand:XF 0 "register_operand" "f")
|
||
(match_operand:XF 1 "register_operand" "f"))
|
||
(set (match_dup 1)
|
||
(match_dup 0))]
|
||
""
|
||
"*
|
||
{
|
||
if (STACK_TOP_P (operands[0]))
|
||
return AS1 (fxch,%1);
|
||
else
|
||
return AS1 (fxch,%0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DI 0 "push_operand" "=<")
|
||
(match_operand:DI 1 "general_operand" "riF"))]
|
||
""
|
||
"* return output_move_double (operands);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DI 0 "push_operand" "=<")
|
||
(match_operand:DI 1 "memory_operand" "o"))]
|
||
"TARGET_PUSH_MEMORY"
|
||
"* return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode),0,0);")
|
||
|
||
(define_expand "movdi"
|
||
[(set (match_operand:DI 0 "general_operand" "")
|
||
(match_operand:DI 1 "general_operand" ""))]
|
||
""
|
||
"
|
||
{
|
||
/* Don't generate memory->memory moves, go through a register */
|
||
if (TARGET_MOVE
|
||
&& no_new_pseudos == 0
|
||
&& GET_CODE (operands[0]) == MEM
|
||
&& GET_CODE (operands[1]) == MEM)
|
||
{
|
||
operands[1] = force_reg (DImode, operands[1]);
|
||
}
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DI 0 "general_operand" "=g,r")
|
||
(match_operand:DI 1 "general_operand" "riF,m"))]
|
||
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
|
||
|| (GET_CODE (operands[1]) != MEM)"
|
||
"* return output_move_double (operands);"
|
||
[(set_attr "type" "integer,memory")
|
||
(set_attr "memory" "*,load")])
|
||
|
||
(define_split
|
||
[(set (match_operand:DI 0 "nonimmediate_operand" "")
|
||
(match_operand:DI 1 "general_operand" ""))]
|
||
"reload_completed
|
||
&& (offsettable_memref_p (operands[0])
|
||
|| nonmemory_operand (operands[0], DImode))
|
||
&& (offsettable_memref_p (operands[1])
|
||
|| nonmemory_operand (operands[1], DImode))
|
||
&& (! reg_overlap_mentioned_p (gen_lowpart (SImode, operands[0]),
|
||
operands[1])
|
||
|| ! reg_overlap_mentioned_p (gen_highpart (SImode, operands[0]),
|
||
operands[1]))"
|
||
[(set (match_dup 2)
|
||
(match_dup 4))
|
||
(set (match_dup 3)
|
||
(match_dup 5))]
|
||
"
|
||
{
|
||
split_di (&operands[0], 1, &operands[2], &operands[3]);
|
||
split_di (&operands[1], 1, &operands[4], &operands[5]);
|
||
|
||
if (reg_overlap_mentioned_p (operands[2], operands[1]))
|
||
{
|
||
rtx tmp;
|
||
|
||
tmp = operands[2];
|
||
operands[2] = operands[3];
|
||
operands[3] = tmp;
|
||
|
||
tmp = operands[4];
|
||
operands[4] = operands[5];
|
||
operands[5] = tmp;
|
||
}
|
||
}")
|
||
|
||
;;- conversion instructions
|
||
;;- NONE
|
||
|
||
;;- zero extension instructions
|
||
;; See comments by `andsi' for when andl is faster than movzx.
|
||
|
||
(define_expand "zero_extendhisi2"
|
||
[(set (match_operand:SI 0 "register_operand" "")
|
||
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
|
||
""
|
||
"")
|
||
|
||
;; When optimizing for the PPro/PII or code size, always use movzwl.
|
||
;; We want to use a different pattern so we can use different constraints
|
||
;; than the generic pattern.
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
|
||
"(optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)"
|
||
"* return AS2 (movz%W0%L0,%1,%0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "register_operand" "=r,&r,?r")
|
||
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,rm,rm")))]
|
||
"! (optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)"
|
||
"*
|
||
{
|
||
rtx xops[2];
|
||
|
||
if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
|
||
&& REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
|
||
{
|
||
xops[0] = operands[0];
|
||
xops[1] = GEN_INT (0xffff);
|
||
output_asm_insn (AS2 (and%L0,%1,%k0), xops);
|
||
RET;
|
||
}
|
||
if (TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1]))
|
||
{
|
||
output_asm_insn (AS2 (xor%L0,%0,%0),operands);
|
||
output_asm_insn (AS2 (mov%W0,%1,%w0),operands);
|
||
RET;
|
||
}
|
||
|
||
if (TARGET_ZERO_EXTEND_WITH_AND)
|
||
{
|
||
xops[0] = operands[0];
|
||
xops[1] = GEN_INT (0xffff);
|
||
if (i386_aligned_p (operands[1]))
|
||
output_asm_insn (AS2 (mov%L0,%k1,%k0),operands);
|
||
else
|
||
output_asm_insn (AS2 (mov%W0,%1,%w0),operands);
|
||
output_asm_insn (AS2 (and%L0,%1,%k0), xops);
|
||
RET;
|
||
}
|
||
|
||
#ifdef INTEL_SYNTAX
|
||
return AS2 (movzx,%1,%0);
|
||
#else
|
||
return AS2 (movz%W0%L0,%1,%0);
|
||
#endif
|
||
}")
|
||
|
||
(define_split
|
||
[(set (match_operand:SI 0 "register_operand" "")
|
||
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
|
||
"reload_completed && TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1])"
|
||
[(set (match_dup 0)
|
||
(const_int 0))
|
||
(set (strict_low_part (match_dup 2))
|
||
(match_dup 1))]
|
||
"operands[2] = gen_rtx_REG (HImode, true_regnum (operands[0]));")
|
||
|
||
|
||
(define_split
|
||
[(set (match_operand:SI 0 "register_operand" "")
|
||
(zero_extend:SI (match_operand:HI 1 "memory_operand" "")))]
|
||
"reload_completed && TARGET_ZERO_EXTEND_WITH_AND && reg_overlap_mentioned_p (operands[0], operands[1])"
|
||
[(set (strict_low_part (match_dup 2))
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(and:SI (match_dup 0)
|
||
(const_int 65535)))]
|
||
"operands[2] = gen_rtx_REG (HImode, true_regnum (operands[0]));")
|
||
|
||
(define_expand "zero_extendqihi2"
|
||
[(set (match_operand:HI 0 "register_operand" "")
|
||
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
|
||
""
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "register_operand" "=r")
|
||
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
|
||
"optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO"
|
||
|
||
"* return AS2 (movz%B0%W0,%1,%0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "register_operand" "=q,&q,?r")
|
||
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))]
|
||
"! (optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)"
|
||
"*
|
||
{
|
||
rtx xops[2];
|
||
|
||
if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
|
||
&& REG_P (operands[1])
|
||
&& REGNO (operands[0]) == REGNO (operands[1]))
|
||
{
|
||
xops[0] = operands[0];
|
||
xops[1] = GEN_INT (0xff);
|
||
output_asm_insn (AS2 (and%L0,%1,%k0), xops);
|
||
RET;
|
||
}
|
||
if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0]))
|
||
{
|
||
if(!reg_overlap_mentioned_p(operands[0],operands[1]))
|
||
{
|
||
output_asm_insn (AS2 (xor%L0,%k0,%k0), operands);
|
||
output_asm_insn (AS2 (mov%B0,%1,%b0), operands);
|
||
}
|
||
else
|
||
{
|
||
xops[0] = operands[0];
|
||
xops[1] = GEN_INT (0xff);
|
||
output_asm_insn (AS2 (mov%B0,%1,%b0),operands);
|
||
output_asm_insn (AS2 (and%L0,%1,%k0), xops);
|
||
}
|
||
RET;
|
||
}
|
||
|
||
#ifdef INTEL_SYNTAX
|
||
return AS2 (movzx,%1,%0);
|
||
#else
|
||
return AS2 (movz%B0%W0,%1,%0);
|
||
#endif
|
||
}")
|
||
|
||
(define_split
|
||
[(set (match_operand:HI 0 "register_operand" "")
|
||
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
|
||
"reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
|
||
&& !reg_overlap_mentioned_p (operands[0], operands[1])"
|
||
[(set (match_dup 0)
|
||
(const_int 0))
|
||
(set (strict_low_part (match_dup 2))
|
||
(match_dup 1))]
|
||
"operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
|
||
|
||
|
||
(define_split
|
||
[(set (match_operand:HI 0 "register_operand" "")
|
||
(zero_extend:HI (match_operand:QI 1 "memory_operand" "")))]
|
||
"reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
|
||
&& reg_overlap_mentioned_p (operands[0], operands[1])"
|
||
[(set (strict_low_part (match_dup 2))
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(and:HI (match_dup 0)
|
||
(const_int 255)))]
|
||
"operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
|
||
|
||
(define_split
|
||
[(set (match_operand:HI 0 "register_operand" "")
|
||
(zero_extend:HI (match_operand:QI 1 "register_operand" "")))]
|
||
"reload_completed && TARGET_ZERO_EXTEND_WITH_AND"
|
||
[(set (match_dup 0)
|
||
(match_dup 2))
|
||
(set (match_dup 0)
|
||
(and:HI (match_dup 0)
|
||
(const_int 255)))]
|
||
"if (GET_CODE (operands[1]) == SUBREG && SUBREG_WORD (operands[1]) == 0)
|
||
operands[1] = SUBREG_REG (operands[1]);
|
||
if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG
|
||
|| REGNO (operands[0]) == REGNO (operands[1]))
|
||
FAIL;
|
||
operands[2] = gen_rtx_REG (HImode, REGNO (operands[1]));")
|
||
|
||
(define_expand "zero_extendqisi2"
|
||
[(set (match_operand:SI 0 "register_operand" "")
|
||
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
|
||
""
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
|
||
"optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO"
|
||
"* return AS2 (movz%B0%L0,%1,%0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "register_operand" "=q,&q,?r")
|
||
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))]
|
||
"! (optimize_size || (int)ix86_cpu == (int)PROCESSOR_PENTIUMPRO)"
|
||
"*
|
||
{
|
||
rtx xops[2];
|
||
|
||
if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
|
||
&& REG_P (operands[1])
|
||
&& REGNO (operands[0]) == REGNO (operands[1]))
|
||
{
|
||
xops[0] = operands[0];
|
||
xops[1] = GEN_INT (0xff);
|
||
output_asm_insn (AS2 (and%L0,%1,%k0), xops);
|
||
RET;
|
||
}
|
||
if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0]))
|
||
{
|
||
if(!reg_overlap_mentioned_p (operands[0], operands[1]))
|
||
{
|
||
output_asm_insn (AS2 (xor%L0,%0,%0),operands);
|
||
output_asm_insn (AS2 (mov%B0,%1,%b0),operands);
|
||
}
|
||
else
|
||
{
|
||
xops[0] = operands[0];
|
||
xops[1] = GEN_INT (0xff);
|
||
output_asm_insn (AS2 (mov%B0,%1,%b0), operands);
|
||
output_asm_insn (AS2 (and%L0,%1,%k0), xops);
|
||
}
|
||
RET;
|
||
}
|
||
|
||
if (TARGET_ZERO_EXTEND_WITH_AND && GET_CODE (operands[1]) == REG)
|
||
{
|
||
xops[0] = operands[0];
|
||
xops[1] = GEN_INT (0xff);
|
||
operands[1] = gen_rtx_REG (SImode, REGNO (operands[1]));
|
||
output_asm_insn (AS2 (mov%L0,%1,%0), operands);
|
||
output_asm_insn (AS2 (and%L0,%1,%k0), xops);
|
||
RET;
|
||
}
|
||
|
||
#ifdef INTEL_SYNTAX
|
||
return AS2 (movzx,%1,%0);
|
||
#else
|
||
return AS2 (movz%B0%L0,%1,%0);
|
||
#endif
|
||
}")
|
||
|
||
(define_split
|
||
[(set (match_operand:SI 0 "register_operand" "")
|
||
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
|
||
"reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
|
||
&& !reg_overlap_mentioned_p (operands[0], operands[1])"
|
||
[(set (match_dup 0)
|
||
(const_int 0))
|
||
(set (strict_low_part (match_dup 2))
|
||
(match_dup 1))]
|
||
"operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
|
||
|
||
|
||
(define_split
|
||
[(set (match_operand:SI 0 "register_operand" "")
|
||
(zero_extend:SI (match_operand:QI 1 "memory_operand" "")))]
|
||
"reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
|
||
&& reg_overlap_mentioned_p (operands[0], operands[1])"
|
||
[(set (strict_low_part (match_dup 2))
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(and:SI (match_dup 0)
|
||
(const_int 255)))]
|
||
"operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
|
||
|
||
(define_split
|
||
[(set (match_operand:SI 0 "register_operand" "")
|
||
(zero_extend:SI (match_operand:QI 1 "register_operand" "")))]
|
||
"reload_completed && TARGET_ZERO_EXTEND_WITH_AND
|
||
&& ! reg_overlap_mentioned_p (operands[0], operands[1])"
|
||
[(set (match_dup 0)
|
||
(match_dup 2))
|
||
(set (match_dup 0)
|
||
(and:SI (match_dup 0)
|
||
(const_int 255)))]
|
||
"operands[2] = gen_rtx_REG (SImode, true_regnum (operands[1]));")
|
||
|
||
(define_insn "zero_extendsidi2"
|
||
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?*o")
|
||
(zero_extend:DI (match_operand:SI 1 "general_operand" "0,rm,r")))]
|
||
""
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:DI 0 "register_operand" "")
|
||
(zero_extend:DI (match_operand:SI 1 "register_operand" "")))]
|
||
"reload_completed && true_regnum (operands[0]) == true_regnum (operands[1])"
|
||
[(set (match_dup 4) (const_int 0))]
|
||
"split_di (&operands[0], 1, &operands[3], &operands[4]);")
|
||
|
||
(define_split
|
||
[(set (match_operand:DI 0 "nonimmediate_operand" "")
|
||
(zero_extend:DI (match_operand:SI 1 "general_operand" "")))]
|
||
"reload_completed"
|
||
[(set (match_dup 3) (match_dup 1))
|
||
(set (match_dup 4) (const_int 0))]
|
||
"split_di (&operands[0], 1, &operands[3], &operands[4]);")
|
||
|
||
;;- sign extension instructions
|
||
|
||
(define_insn "extendsidi2"
|
||
[(set (match_operand:DI 0 "nonimmediate_operand" "=A,?r,?Ar,*o")
|
||
(sign_extend:DI (match_operand:SI 1 "register_operand" "0,0,r,*r")))
|
||
(clobber (match_scratch:SI 2 "=X,X,X,&r"))]
|
||
""
|
||
"#")
|
||
|
||
;; Extend to memory case when source register does die.
|
||
(define_split
|
||
[(set (match_operand:DI 0 "memory_operand" "")
|
||
(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
|
||
(clobber (match_operand:SI 2 "register_operand" ""))]
|
||
"(flow2_completed
|
||
&& dead_or_set_p (insn, operands[1])
|
||
&& !reg_mentioned_p (operands[1], operands[0]))"
|
||
[(set (match_dup 3) (match_dup 1))
|
||
(set (match_dup 1) (ashiftrt:SI (match_dup 1) (const_int 31)))
|
||
(set (match_dup 4) (match_dup 1))]
|
||
"split_di (&operands[0], 1, &operands[3], &operands[4]);")
|
||
|
||
;; Extend to memory case when source register does not die.
|
||
(define_split
|
||
[(set (match_operand:DI 0 "memory_operand" "")
|
||
(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
|
||
(clobber (match_operand:SI 2 "register_operand" ""))]
|
||
"flow2_completed"
|
||
[(const_int 0)]
|
||
"
|
||
{
|
||
split_di (&operands[0], 1, &operands[3], &operands[4]);
|
||
|
||
emit_move_insn (operands[3], operands[1]);
|
||
|
||
/* Generate a cltd if possible and doing so it profitable. */
|
||
if (true_regnum (operands[1]) == 0
|
||
&& true_regnum (operands[2]) == 1
|
||
&& (optimize_size || !TARGET_PENTIUM))
|
||
{
|
||
emit_insn (gen_ashrsi3_31 (operands[2], operands[1]));
|
||
}
|
||
else
|
||
{
|
||
emit_move_insn (operands[2], operands[1]);
|
||
emit_insn (gen_ashrsi3_31 (operands[2], operands[2]));
|
||
}
|
||
emit_move_insn (operands[4], operands[2]);
|
||
DONE;
|
||
}")
|
||
|
||
;; Extend to register case. Optimize case where source and destination
|
||
;; registers match and cases where we can use cltd.
|
||
(define_split
|
||
[(set (match_operand:DI 0 "register_operand" "")
|
||
(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
|
||
(clobber (match_scratch:SI 2 ""))]
|
||
"reload_completed"
|
||
[(const_int 0)]
|
||
"
|
||
{
|
||
split_di (&operands[0], 1, &operands[3], &operands[4]);
|
||
|
||
if (true_regnum (operands[3]) != true_regnum (operands[1]))
|
||
emit_move_insn (operands[3], operands[1]);
|
||
|
||
/* Generate a cltd if possible and doing so it profitable. */
|
||
if (true_regnum (operands[3]) == 0
|
||
&& (optimize_size || !TARGET_PENTIUM))
|
||
{
|
||
emit_insn (gen_ashrsi3_31 (operands[4], operands[3]));
|
||
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]));
|
||
DONE;
|
||
}")
|
||
|
||
;; Note that the i386 programmers' manual says that the opcodes
|
||
;; are named movsx..., but the assembler on Unix does not accept that.
|
||
;; We use what the Unix assembler expects.
|
||
|
||
(define_insn "extendhisi2"
|
||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REGNO (operands[0]) == 0
|
||
&& REG_P (operands[1]) && REGNO (operands[1]) == 0
|
||
&& (optimize_size || ix86_cpu != PROCESSOR_K6))
|
||
#ifdef INTEL_SYNTAX
|
||
return \"cwde\";
|
||
#else
|
||
return \"cwtl\";
|
||
#endif
|
||
|
||
#ifdef INTEL_SYNTAX
|
||
return AS2 (movsx,%1,%0);
|
||
#else
|
||
return AS2 (movs%W0%L0,%1,%0);
|
||
#endif
|
||
}")
|
||
|
||
(define_insn "extendqihi2"
|
||
[(set (match_operand:HI 0 "register_operand" "=r")
|
||
(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REGNO (operands[0]) == 0
|
||
&& REG_P (operands[1]) && REGNO (operands[1]) == 0
|
||
&& (optimize_size || ix86_cpu != PROCESSOR_K6))
|
||
return \"cbtw\";
|
||
|
||
#ifdef INTEL_SYNTAX
|
||
return AS2 (movsx,%1,%0);
|
||
#else
|
||
return AS2 (movs%B0%W0,%1,%0);
|
||
#endif
|
||
}")
|
||
|
||
(define_insn "extendqisi2"
|
||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||
(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
|
||
""
|
||
"*
|
||
{
|
||
#ifdef INTEL_SYNTAX
|
||
return AS2 (movsx,%1,%0);
|
||
#else
|
||
return AS2 (movs%B0%L0,%1,%0);
|
||
#endif
|
||
}")
|
||
|
||
|
||
;; Truncation of long long -> 32 bit
|
||
|
||
(define_expand "truncdisi2"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
|
||
(truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))]
|
||
""
|
||
"
|
||
{
|
||
/* Don't generate memory->memory moves, go through a register */
|
||
if (TARGET_MOVE
|
||
&& (reload_in_progress | reload_completed) == 0
|
||
&& GET_CODE (operands[0]) == MEM
|
||
&& GET_CODE (operands[1]) == MEM)
|
||
{
|
||
rtx target = gen_reg_rtx (SImode);
|
||
emit_insn (gen_truncdisi2 (target, operands[1]));
|
||
emit_move_insn (operands[0], target);
|
||
DONE;
|
||
}
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
|
||
(truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))]
|
||
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
rtx low[2], high[2], xops[2];
|
||
|
||
split_di (&operands[1], 1, low, high);
|
||
xops[0] = operands[0];
|
||
xops[1] = low[0];
|
||
if (!rtx_equal_p (xops[0], xops[1]))
|
||
output_asm_insn (AS2 (mov%L0,%1,%0), xops);
|
||
|
||
RET;
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
|
||
(truncate:SI (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
|
||
(const_int 32))))]
|
||
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
rtx low[2], high[2], xops[2];
|
||
|
||
split_di (&operands[1], 1, low, high);
|
||
xops[0] = operands[0];
|
||
xops[1] = high[0];
|
||
if (!rtx_equal_p (xops[0], xops[1]))
|
||
output_asm_insn (AS2 (mov%L0,%1,%0), xops);
|
||
|
||
RET;
|
||
}")
|
||
|
||
|
||
|
||
;; Conversions between float and double.
|
||
|
||
(define_expand "extendsfdf2"
|
||
[(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
|
||
(float_extend:DF
|
||
(match_operand:SF 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))
|
||
(clobber (match_dup 3))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
|
||
operands[1] = force_reg (SFmode, operands[1]);
|
||
|
||
operands[2] = assign_386_stack_local (SFmode, 0);
|
||
operands[3] = assign_386_stack_local (DFmode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,!f,!*r")
|
||
(float_extend:DF
|
||
(match_operand:SF 1 "nonimmediate_operand" "fm,f,*r,f")))
|
||
(clobber (match_operand:SF 2 "memory_operand" "m,m,m,m"))
|
||
(clobber (match_operand:DF 3 "memory_operand" "m,m,m,o"))]
|
||
"TARGET_80387 && (GET_CODE (operands[0]) != MEM
|
||
|| GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
output_float_extend (insn, operands);
|
||
return \"\";
|
||
}"
|
||
[(set_attr "type" "fld,fpop,fld,fpop")])
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(float_extend:DF (match_operand:SF 1 "register_operand" "")))
|
||
(clobber (match_operand:SF 2 "memory_operand" ""))
|
||
(clobber (match_operand:DF 3 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[1])"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float_extend:DF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(float_extend:DF (match_operand:SF 1 "register_operand" "")))
|
||
(clobber (match_operand:SF 2 "memory_operand" ""))
|
||
(clobber (match_operand:DF 3 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[0])"
|
||
[(set (match_dup 3)
|
||
(float_extend:DF (match_dup 1)))
|
||
(set (match_dup 0)
|
||
(match_dup 3))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "nonimmediate_operand" "")
|
||
(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "")))
|
||
(clobber (match_operand:SF 2 "memory_operand" ""))
|
||
(clobber (match_operand:DF 3 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float_extend:DF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "nonimmediate_operand" "=f,m")
|
||
(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
|
||
"TARGET_80387 && (GET_CODE (operands[0]) != MEM
|
||
|| GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
output_float_extend (insn, operands);
|
||
return \"\";
|
||
}"
|
||
[(set_attr "type" "fld,fpop")])
|
||
|
||
(define_expand "extenddfxf2"
|
||
[(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "")
|
||
(float_extend:XF
|
||
(match_operand:DF 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))
|
||
(clobber (match_dup 3))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
|
||
operands[1] = force_reg (DFmode, operands[1]);
|
||
|
||
operands[2] = assign_386_stack_local (DFmode, 0);
|
||
operands[3] = assign_386_stack_local (XFmode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,!f,!*r")
|
||
(float_extend:XF
|
||
(match_operand:DF 1 "nonimmediate_operand" "fm,f,*r,f")))
|
||
(clobber (match_operand:DF 2 "memory_operand" "m,m,o,m"))
|
||
(clobber (match_operand:XF 3 "memory_operand" "m,m,m,o"))]
|
||
"TARGET_80387 && (GET_CODE (operands[0]) != MEM
|
||
|| GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
output_float_extend (insn, operands);
|
||
return \"\";
|
||
}"
|
||
[(set_attr "type" "fld,fpop,fld,fpop")])
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(float_extend:XF (match_operand:DF 1 "register_operand" "")))
|
||
(clobber (match_operand:DF 2 "memory_operand" ""))
|
||
(clobber (match_operand:XF 3 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[1])"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float_extend:XF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(float_extend:XF (match_operand:DF 1 "register_operand" "")))
|
||
(clobber (match_operand:DF 2 "memory_operand" ""))
|
||
(clobber (match_operand:XF 3 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[0])"
|
||
[(set (match_dup 3)
|
||
(float_extend:XF (match_dup 1)))
|
||
(set (match_dup 0)
|
||
(match_dup 3))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "nonimmediate_operand" "")
|
||
(float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "")))
|
||
(clobber (match_operand:DF 2 "memory_operand" ""))
|
||
(clobber (match_operand:XF 3 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float_extend:XF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "nonimmediate_operand" "=f,m")
|
||
(float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "fm,f")))]
|
||
"TARGET_80387 && (GET_CODE (operands[0]) != MEM
|
||
|| GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
output_float_extend (insn, operands);
|
||
return \"\";
|
||
}"
|
||
[(set_attr "type" "fld,fpop")])
|
||
|
||
(define_expand "extendsfxf2"
|
||
[(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "")
|
||
(float_extend:XF
|
||
(match_operand:SF 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))
|
||
(clobber (match_dup 3))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
|
||
operands[1] = force_reg (SFmode, operands[1]);
|
||
|
||
operands[2] = assign_386_stack_local (SFmode, 0);
|
||
operands[3] = assign_386_stack_local (XFmode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,!f,!*r")
|
||
(float_extend:XF
|
||
(match_operand:SF 1 "nonimmediate_operand" "fm,f,*r,f")))
|
||
(clobber (match_operand:SF 2 "memory_operand" "m,m,m,m"))
|
||
(clobber (match_operand:XF 3 "memory_operand" "m,m,m,o"))]
|
||
"TARGET_80387 && (GET_CODE (operands[0]) != MEM
|
||
|| GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
output_float_extend (insn, operands);
|
||
return \"\";
|
||
}"
|
||
[(set_attr "type" "fld,fpop,fld,fpop")])
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(float_extend:XF (match_operand:SF 1 "register_operand" "")))
|
||
(clobber (match_operand:SF 2 "memory_operand" ""))
|
||
(clobber (match_operand:XF 3 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[1])"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float_extend:XF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(float_extend:XF (match_operand:SF 1 "register_operand" "")))
|
||
(clobber (match_operand:SF 2 "memory_operand" ""))
|
||
(clobber (match_operand:XF 3 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed && NON_STACK_REG_P (operands[0])"
|
||
[(set (match_dup 3)
|
||
(float_extend:XF (match_dup 1)))
|
||
(set (match_dup 0)
|
||
(match_dup 3))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "nonimmediate_operand" "")
|
||
(float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "")))
|
||
(clobber (match_operand:SF 2 "memory_operand" ""))
|
||
(clobber (match_operand:XF 3 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float_extend:XF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "nonimmediate_operand" "=f,m")
|
||
(float_extend:XF
|
||
(match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
|
||
"TARGET_80387 && (GET_CODE (operands[0]) != MEM
|
||
|| GET_CODE (operands[1]) != MEM)"
|
||
"*
|
||
{
|
||
output_float_extend (insn, operands);
|
||
return \"\";
|
||
}"
|
||
[(set_attr "type" "fld,fpop")])
|
||
|
||
(define_expand "truncdfsf2"
|
||
[(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
|
||
(float_truncate:SF
|
||
(match_operand:DF 1 "register_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
operands[2] = (rtx) assign_386_stack_local (SFmode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,!*r")
|
||
(float_truncate:SF
|
||
(match_operand:DF 1 "register_operand" "0,f,f")))
|
||
(clobber (match_operand:SF 2 "memory_operand" "m,m,m"))]
|
||
"TARGET_80387"
|
||
"*
|
||
{
|
||
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
|
||
rtx xops[1];
|
||
|
||
xops[0] = GET_CODE (operands[0]) == MEM ? operands[0] : operands[2];
|
||
|
||
if (stack_top_dies || STACK_REG_P (operands[0]))
|
||
output_asm_insn (AS1 (fstp%z0,%0), xops);
|
||
else
|
||
output_asm_insn (AS1 (fst%z0,%0), xops);
|
||
|
||
if (STACK_REG_P (operands[0]))
|
||
return AS1 (fld%z2,%2);
|
||
else if (NON_STACK_REG_P (operands[0]))
|
||
return AS2 (mov%L0,%2,%0);
|
||
|
||
return \"\";
|
||
}"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(float_truncate:SF (match_operand:DF 1 "register_operand" "")))
|
||
(clobber (match_operand:SF 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(float_truncate:SF (match_dup 1)))
|
||
(set (match_dup 0)
|
||
(match_dup 2))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "memory_operand" "")
|
||
(float_truncate:SF (match_operand:DF 1 "register_operand" "")))
|
||
(clobber (match_operand:SF 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float_truncate:SF (match_dup 1)))]
|
||
"")
|
||
|
||
;; This cannot output into an f-reg because there is no way to be sure
|
||
;; of truncating in that case.
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "memory_operand" "=m")
|
||
(float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
|
||
"TARGET_80387"
|
||
"*
|
||
{
|
||
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
|
||
|
||
if (stack_top_dies)
|
||
return AS1 (fstp%z0,%0);
|
||
else
|
||
return AS1 (fst%z0,%0);
|
||
}"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "truncxfsf2"
|
||
[(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
|
||
(float_truncate:SF
|
||
(match_operand:XF 1 "register_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
operands[2] = (rtx) assign_386_stack_local (SFmode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,!*r")
|
||
(float_truncate:SF
|
||
(match_operand:XF 1 "register_operand" "0,f,f")))
|
||
(clobber (match_operand:SF 2 "memory_operand" "m,m,m"))]
|
||
"TARGET_80387"
|
||
"*
|
||
{
|
||
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
|
||
rtx xops[1];
|
||
|
||
xops[0] = GET_CODE (operands[0]) == MEM ? operands[0] : operands[2];
|
||
|
||
if (stack_top_dies || STACK_REG_P (operands[0]))
|
||
output_asm_insn (AS1 (fstp%z0,%0), xops);
|
||
else
|
||
output_asm_insn (AS1 (fst%z0,%0), xops);
|
||
|
||
if (STACK_REG_P (operands[0]))
|
||
return AS1 (fld%z2,%2);
|
||
else if (NON_STACK_REG_P (operands[0]))
|
||
return AS2 (mov%L0,%2,%0);
|
||
|
||
return \"\";
|
||
}"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(float_truncate:SF (match_operand:XF 1 "register_operand" "")))
|
||
(clobber (match_operand:SF 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(float_truncate:SF (match_dup 1)))
|
||
(set (match_dup 0)
|
||
(match_dup 2))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "memory_operand" "")
|
||
(float_truncate:SF (match_operand:XF 1 "register_operand" "")))
|
||
(clobber (match_operand:SF 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float_truncate:SF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "memory_operand" "=m")
|
||
(float_truncate:SF (match_operand:XF 1 "register_operand" "f")))]
|
||
"TARGET_80387"
|
||
"*
|
||
{
|
||
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
|
||
|
||
if (stack_top_dies)
|
||
return AS1 (fstp%z0,%0);
|
||
else
|
||
return AS1 (fst%z0,%0);
|
||
}"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "truncxfdf2"
|
||
[(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
|
||
(float_truncate:DF
|
||
(match_operand:XF 1 "register_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
operands[2] = (rtx) assign_386_stack_local (DFmode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,!*r")
|
||
(float_truncate:DF
|
||
(match_operand:XF 1 "register_operand" "0,f,f")))
|
||
(clobber (match_operand:DF 2 "memory_operand" "m,m,o"))]
|
||
"TARGET_80387"
|
||
"*
|
||
{
|
||
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
|
||
rtx xops[2];
|
||
|
||
xops[0] = GET_CODE (operands[0]) == MEM ? operands[0] : operands[2];
|
||
|
||
if (stack_top_dies || STACK_REG_P (operands[0]))
|
||
output_asm_insn (AS1 (fstp%z0,%0), xops);
|
||
else
|
||
output_asm_insn (AS1 (fst%z0,%0), xops);
|
||
|
||
if (STACK_REG_P (operands[0]))
|
||
return AS1 (fld%z2,%2);
|
||
else if (NON_STACK_REG_P (operands[0]))
|
||
{
|
||
xops[0] = operands[0];
|
||
xops[1] = operands[2];
|
||
output_asm_insn (output_move_double (xops), xops);
|
||
}
|
||
|
||
return \"\";
|
||
}"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(float_truncate:DF (match_operand:XF 1 "register_operand" "")))
|
||
(clobber (match_operand:DF 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(float_truncate:DF (match_dup 1)))
|
||
(set (match_dup 0)
|
||
(match_dup 2))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "memory_operand" "")
|
||
(float_truncate:DF (match_operand:XF 1 "register_operand" "")))
|
||
(clobber (match_operand:DF 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float_truncate:DF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "memory_operand" "=m")
|
||
(float_truncate:DF (match_operand:XF 1 "register_operand" "f")))]
|
||
"TARGET_80387"
|
||
"*
|
||
{
|
||
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
|
||
|
||
if (stack_top_dies)
|
||
return AS1 (fstp%z0,%0);
|
||
else
|
||
return AS1 (fst%z0,%0);
|
||
}"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
;; Conversions between floating point and fix point.
|
||
|
||
(define_expand "fix_truncsfsi2"
|
||
[(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
||
(fix:SI (fix:SF (match_operand:SF 1 "register_operand" ""))))
|
||
(clobber (match_dup 2))
|
||
(clobber (match_dup 3))
|
||
(clobber (match_dup 4))
|
||
(clobber (match_scratch:HI 5 ""))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
operands[2] = (rtx) assign_386_stack_local (HImode, 0);
|
||
operands[3] = (rtx) assign_386_stack_local (HImode, 1);
|
||
operands[4] = (rtx) assign_386_stack_local (SImode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=m,!&r")
|
||
(fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f,f"))))
|
||
(clobber (match_operand:HI 2 "memory_operand" "m,m"))
|
||
(clobber (match_operand:HI 3 "memory_operand" "m,m"))
|
||
(clobber (match_operand:SI 4 "memory_operand" "m,m"))
|
||
(clobber (match_scratch:HI 5 "=&r,&r"))]
|
||
"TARGET_80387"
|
||
"* return output_fix_trunc (insn, operands);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "fix_truncsfdi2"
|
||
[(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
|
||
(fix:DI (fix:SF (match_operand:SF 1 "register_operand" ""))))
|
||
(clobber (match_dup 1))
|
||
(clobber (match_dup 2))
|
||
(clobber (match_dup 3))
|
||
(clobber (match_dup 4))
|
||
(clobber (match_scratch:HI 5 ""))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
operands[1] = copy_to_mode_reg (SFmode, operands[1]);
|
||
operands[2] = (rtx) assign_386_stack_local (HImode, 0);
|
||
operands[3] = (rtx) assign_386_stack_local (HImode, 1);
|
||
operands[4] = (rtx) assign_386_stack_local (DImode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DI 0 "nonimmediate_operand" "=m,!&r")
|
||
(fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f,f"))))
|
||
(clobber (match_dup 1))
|
||
(clobber (match_operand:HI 2 "memory_operand" "m,m"))
|
||
(clobber (match_operand:HI 3 "memory_operand" "m,m"))
|
||
(clobber (match_operand:DI 4 "memory_operand" "m,o"))
|
||
(clobber (match_scratch:HI 5 "=&r,&r"))]
|
||
"TARGET_80387"
|
||
"* return output_fix_trunc (insn, operands);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "fix_truncdfsi2"
|
||
[(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
||
(fix:SI (fix:DF (match_operand:DF 1 "register_operand" ""))))
|
||
(clobber (match_dup 2))
|
||
(clobber (match_dup 3))
|
||
(clobber (match_dup 4))
|
||
(clobber (match_scratch:HI 5 ""))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
operands[2] = (rtx) assign_386_stack_local (HImode, 0);
|
||
operands[3] = (rtx) assign_386_stack_local (HImode, 1);
|
||
operands[4] = (rtx) assign_386_stack_local (SImode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=m,!&r")
|
||
(fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f,f"))))
|
||
(clobber (match_operand:HI 2 "memory_operand" "m,m"))
|
||
(clobber (match_operand:HI 3 "memory_operand" "m,m"))
|
||
(clobber (match_operand:SI 4 "memory_operand" "m,m"))
|
||
(clobber (match_scratch:HI 5 "=&r,&r"))]
|
||
"TARGET_80387"
|
||
"* return output_fix_trunc (insn, operands);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "fix_truncdfdi2"
|
||
[(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
|
||
(fix:DI (fix:DF (match_operand:DF 1 "register_operand" ""))))
|
||
(clobber (match_dup 1))
|
||
(clobber (match_dup 2))
|
||
(clobber (match_dup 3))
|
||
(clobber (match_dup 4))
|
||
(clobber (match_scratch:HI 5 ""))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
operands[1] = copy_to_mode_reg (DFmode, operands[1]);
|
||
operands[2] = (rtx) assign_386_stack_local (HImode, 0);
|
||
operands[3] = (rtx) assign_386_stack_local (HImode, 1);
|
||
operands[4] = (rtx) assign_386_stack_local (DImode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DI 0 "nonimmediate_operand" "=m,!&r")
|
||
(fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f,f"))))
|
||
(clobber (match_dup 1))
|
||
(clobber (match_operand:HI 2 "memory_operand" "m,m"))
|
||
(clobber (match_operand:HI 3 "memory_operand" "m,m"))
|
||
(clobber (match_operand:DI 4 "memory_operand" "m,o"))
|
||
(clobber (match_scratch:HI 5 "=&r,&r"))]
|
||
"TARGET_80387"
|
||
"* return output_fix_trunc (insn, operands);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "fix_truncxfsi2"
|
||
[(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
||
(fix:SI (fix:XF (match_operand:XF 1 "register_operand" ""))))
|
||
(clobber (match_dup 2))
|
||
(clobber (match_dup 3))
|
||
(clobber (match_dup 4))
|
||
(clobber (match_scratch:HI 5 ""))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
operands[2] = (rtx) assign_386_stack_local (HImode, 0);
|
||
operands[3] = (rtx) assign_386_stack_local (HImode, 1);
|
||
operands[4] = (rtx) assign_386_stack_local (SImode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=m,!&r")
|
||
(fix:SI (fix:XF (match_operand:XF 1 "register_operand" "f,f"))))
|
||
(clobber (match_operand:HI 2 "memory_operand" "m,m"))
|
||
(clobber (match_operand:HI 3 "memory_operand" "m,m"))
|
||
(clobber (match_operand:SI 4 "memory_operand" "m,m"))
|
||
(clobber (match_scratch:HI 5 "=&r,&r"))]
|
||
"TARGET_80387"
|
||
"* return output_fix_trunc (insn, operands);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "fix_truncxfdi2"
|
||
[(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
|
||
(fix:DI (fix:XF (match_operand:XF 1 "register_operand" ""))))
|
||
(clobber (match_dup 1))
|
||
(clobber (match_dup 2))
|
||
(clobber (match_dup 3))
|
||
(clobber (match_dup 4))
|
||
(clobber (match_scratch:HI 5 ""))])]
|
||
"TARGET_80387"
|
||
"
|
||
{
|
||
operands[1] = copy_to_mode_reg (XFmode, operands[1]);
|
||
operands[2] = (rtx) assign_386_stack_local (HImode, 0);
|
||
operands[3] = (rtx) assign_386_stack_local (HImode, 1);
|
||
operands[4] = (rtx) assign_386_stack_local (DImode, 0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DI 0 "nonimmediate_operand" "=m,!&r")
|
||
(fix:DI (fix:XF (match_operand:XF 1 "register_operand" "f,f"))))
|
||
(clobber (match_dup 1))
|
||
(clobber (match_operand:HI 2 "memory_operand" "m,m"))
|
||
(clobber (match_operand:HI 3 "memory_operand" "m,m"))
|
||
(clobber (match_operand:DI 4 "memory_operand" "m,o"))
|
||
(clobber (match_scratch:HI 5 "=&r,&r"))]
|
||
"TARGET_80387"
|
||
"* return output_fix_trunc (insn, operands);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
;; Conversion between fixed point and floating point.
|
||
|
||
;; ??? Possibly represent floatunssidf2 here in gcc2.
|
||
|
||
(define_expand "floatsisf2"
|
||
[(parallel [(set (match_operand:SF 0 "register_operand" "")
|
||
(float:SF (match_operand:SI 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"operands[2] = assign_386_stack_local (SImode, 0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
||
(float:SF (match_operand:SI 1 "nonimmediate_operand" "m,!r")))
|
||
(clobber (match_operand:SI 2 "memory_operand" "m,m"))]
|
||
"TARGET_80387"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(float:SF (match_operand:SI 1 "memory_operand" "")))
|
||
(clobber (match_operand:SI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float:SF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(float:SF (match_operand:SI 1 "register_operand" "")))
|
||
(clobber (match_operand:SI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float:SF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "register_operand" "=f")
|
||
(float:SF (match_operand:SI 1 "memory_operand" "m")))]
|
||
"TARGET_80387"
|
||
"* return AS1 (fild%z1,%1);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "floathisf2"
|
||
[(parallel [(set (match_operand:SF 0 "register_operand" "")
|
||
(float:SF (match_operand:HI 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"operands[2] = assign_386_stack_local (HImode, 0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
||
(float:SF (match_operand:HI 1 "nonimmediate_operand" "m,!r")))
|
||
(clobber (match_operand:HI 2 "memory_operand" "m,m"))]
|
||
"TARGET_80387"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(float:SF (match_operand:HI 1 "memory_operand" "")))
|
||
(clobber (match_operand:HI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float:SF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(float:SF (match_operand:HI 1 "register_operand" "")))
|
||
(clobber (match_operand:HI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float:SF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "register_operand" "=f")
|
||
(float:SF (match_operand:HI 1 "memory_operand" "m")))]
|
||
"TARGET_80387"
|
||
"* return AS1 (fild%z1,%1);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "floatdisf2"
|
||
[(parallel [(set (match_operand:SF 0 "register_operand" "")
|
||
(float:SF (match_operand:DI 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"operands[2] = assign_386_stack_local (DImode, 0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
||
(float:SF (match_operand:DI 1 "nonimmediate_operand" "m,!r")))
|
||
(clobber (match_operand:DI 2 "memory_operand" "m,o"))]
|
||
"TARGET_80387"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(float:SF (match_operand:DI 1 "memory_operand" "")))
|
||
(clobber (match_operand:DI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float:SF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(float:SF (match_operand:DI 1 "register_operand" "")))
|
||
(clobber (match_operand:DI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float:SF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "register_operand" "=f")
|
||
(float:SF (match_operand:DI 1 "memory_operand" "m")))]
|
||
"TARGET_80387"
|
||
"* return AS1 (fild%z1,%1);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "floatsidf2"
|
||
[(parallel [(set (match_operand:DF 0 "register_operand" "")
|
||
(float:DF (match_operand:SI 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"operands[2] = assign_386_stack_local (SImode, 0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f,f")
|
||
(float:DF (match_operand:SI 1 "nonimmediate_operand" "m,!r")))
|
||
(clobber (match_operand:SI 2 "memory_operand" "m,m"))]
|
||
"TARGET_80387"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(float:DF (match_operand:SI 1 "memory_operand" "")))
|
||
(clobber (match_operand:SI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float:DF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(float:DF (match_operand:SI 1 "register_operand" "")))
|
||
(clobber (match_operand:SI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float:DF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(float:DF (match_operand:SI 1 "memory_operand" "m")))]
|
||
"TARGET_80387"
|
||
"* return AS1 (fild%z1,%1);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "floathidf2"
|
||
[(parallel [(set (match_operand:DF 0 "register_operand" "")
|
||
(float:DF (match_operand:HI 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"operands[2] = assign_386_stack_local (HImode, 0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f,f")
|
||
(float:DF (match_operand:HI 1 "nonimmediate_operand" "m,!r")))
|
||
(clobber (match_operand:HI 2 "memory_operand" "m,m"))]
|
||
"TARGET_80387"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(float:DF (match_operand:HI 1 "memory_operand" "")))
|
||
(clobber (match_operand:HI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float:DF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(float:DF (match_operand:HI 1 "register_operand" "")))
|
||
(clobber (match_operand:HI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float:DF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(float:DF (match_operand:HI 1 "memory_operand" "m")))]
|
||
"TARGET_80387"
|
||
"* return AS1 (fild%z1,%1);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "floatdidf2"
|
||
[(parallel [(set (match_operand:DF 0 "register_operand" "")
|
||
(float:DF (match_operand:DI 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"operands[2] = assign_386_stack_local (DImode, 0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f,f")
|
||
(float:DF (match_operand:DI 1 "nonimmediate_operand" "m,!r")))
|
||
(clobber (match_operand:DI 2 "memory_operand" "m,o"))]
|
||
"TARGET_80387"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(float:DF (match_operand:DI 1 "memory_operand" "")))
|
||
(clobber (match_operand:DI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float:DF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(float:DF (match_operand:DI 1 "register_operand" "")))
|
||
(clobber (match_operand:DI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float:DF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(float:DF (match_operand:DI 1 "memory_operand" "m")))]
|
||
"TARGET_80387"
|
||
"* return AS1 (fild%z1,%1);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "floatsixf2"
|
||
[(parallel [(set (match_operand:XF 0 "register_operand" "")
|
||
(float:XF (match_operand:SI 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"operands[2] = assign_386_stack_local (SImode, 0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f,f")
|
||
(float:XF (match_operand:SI 1 "nonimmediate_operand" "m,!r")))
|
||
(clobber (match_operand:SI 2 "memory_operand" "m,m"))]
|
||
"TARGET_80387"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(float:XF (match_operand:SI 1 "memory_operand" "")))
|
||
(clobber (match_operand:SI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float:XF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(float:XF (match_operand:SI 1 "register_operand" "")))
|
||
(clobber (match_operand:SI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float:XF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(float:XF (match_operand:SI 1 "memory_operand" "m")))]
|
||
"TARGET_80387"
|
||
"* return AS1 (fild%z1,%1);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "floathixf2"
|
||
[(parallel [(set (match_operand:XF 0 "register_operand" "")
|
||
(float:XF (match_operand:HI 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"operands[2] = assign_386_stack_local (HImode, 0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f,f")
|
||
(float:XF (match_operand:HI 1 "nonimmediate_operand" "m,!r")))
|
||
(clobber (match_operand:HI 2 "memory_operand" "m,m"))]
|
||
"TARGET_80387"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(float:XF (match_operand:HI 1 "memory_operand" "")))
|
||
(clobber (match_operand:HI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float:XF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(float:XF (match_operand:HI 1 "register_operand" "")))
|
||
(clobber (match_operand:HI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float:XF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(float:XF (match_operand:HI 1 "memory_operand" "m")))]
|
||
"TARGET_80387"
|
||
"* return AS1 (fild%z1,%1);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_expand "floatdixf2"
|
||
[(parallel [(set (match_operand:XF 0 "register_operand" "")
|
||
(float:XF (match_operand:DI 1 "nonimmediate_operand" "")))
|
||
(clobber (match_dup 2))])]
|
||
"TARGET_80387"
|
||
"operands[2] = assign_386_stack_local (DImode, 0);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f,f")
|
||
(float:XF (match_operand:DI 1 "nonimmediate_operand" "m,!r")))
|
||
(clobber (match_operand:DI 2 "memory_operand" "m,o"))]
|
||
"TARGET_80387"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(float:XF (match_operand:DI 1 "memory_operand" "")))
|
||
(clobber (match_operand:DI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 0)
|
||
(float:XF (match_dup 1)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(float:XF (match_operand:DI 1 "register_operand" "")))
|
||
(clobber (match_operand:DI 2 "memory_operand" ""))]
|
||
"TARGET_80387 && reload_completed"
|
||
[(set (match_dup 2)
|
||
(match_dup 1))
|
||
(set (match_dup 0)
|
||
(float:XF (match_dup 2)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(float:XF (match_operand:DI 1 "memory_operand" "m")))]
|
||
"TARGET_80387"
|
||
"* return AS1 (fild%z1,%1);"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
;;- add instructions
|
||
|
||
(define_insn "*addsidi3_1"
|
||
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,!&r,!r,o,!o")
|
||
(plus:DI (match_operand:DI 1 "general_operand" "0,0,0,o,riF,riF,o")
|
||
(zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,roi,roi,ri,ri"))))
|
||
(clobber (match_scratch:SI 3 "=X,X,X,X,X,X,&r"))]
|
||
""
|
||
"*
|
||
{
|
||
rtx low[3], high[3], xops[7];
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
split_di (operands, 2, low, high);
|
||
high[2] = const0_rtx;
|
||
low[2] = operands[2];
|
||
|
||
if (!rtx_equal_p (operands[0], operands[1]))
|
||
{
|
||
xops[0] = high[0];
|
||
xops[1] = low[0];
|
||
xops[2] = high[1];
|
||
xops[3] = low[1];
|
||
|
||
if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
|
||
{
|
||
output_asm_insn (AS2 (mov%L1,%3,%1), xops);
|
||
output_asm_insn (AS2 (mov%L0,%2,%0), xops);
|
||
}
|
||
else
|
||
{
|
||
xops[4] = high[2];
|
||
xops[5] = low[2];
|
||
xops[6] = operands[3];
|
||
output_asm_insn (AS2 (mov%L6,%3,%6), xops);
|
||
output_asm_insn (AS2 (add%L6,%5,%6), xops);
|
||
output_asm_insn (AS2 (mov%L1,%6,%1), xops);
|
||
output_asm_insn (AS2 (mov%L6,%2,%6), xops);
|
||
output_asm_insn (AS2 (adc%L6,%4,%6), xops);
|
||
output_asm_insn (AS2 (mov%L0,%6,%0), xops);
|
||
RET;
|
||
}
|
||
}
|
||
|
||
output_asm_insn (AS2 (add%L0,%2,%0), low);
|
||
output_asm_insn (AS2 (adc%L0,%2,%0), high);
|
||
cc_status.value1 = high[0];
|
||
cc_status.flags = CC_NO_OVERFLOW;
|
||
RET;
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_insn "addsidi3_2"
|
||
[(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,&r,!&r,&r,o,o,!o")
|
||
(plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,o,o,ri,ri,i,r"))
|
||
(match_operand:DI 1 "general_operand" "0,0,0,iF,ro,roiF,riF,o,o")))
|
||
(clobber (match_scratch:SI 3 "=X,X,X,X,X,X,X,&r,&r"))]
|
||
""
|
||
"*
|
||
{
|
||
rtx low[3], high[3], xops[7];
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
split_di (operands, 2, low, high);
|
||
high[2] = const0_rtx;
|
||
low[2] = operands[2];
|
||
|
||
if (!rtx_equal_p (operands[0], operands[1]))
|
||
{
|
||
xops[0] = high[0];
|
||
xops[1] = low[0];
|
||
xops[2] = high[1];
|
||
xops[3] = low[1];
|
||
|
||
if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
|
||
{
|
||
if (rtx_equal_p (low[0], operands[2]))
|
||
{
|
||
output_asm_insn (AS2 (mov%L0,%2,%0), high);
|
||
output_asm_insn (AS2 (add%L0,%1,%0), low);
|
||
output_asm_insn (AS2 (adc%L0,%1,%0), high);
|
||
RET;
|
||
}
|
||
if (rtx_equal_p (high[0], operands[2]))
|
||
{
|
||
if (GET_CODE (operands[0]) != MEM)
|
||
{
|
||
output_asm_insn (AS2 (mov%L0,%2,%0), low);
|
||
output_asm_insn (AS2 (mov%L0,%2,%0), high);
|
||
output_asm_insn (AS2 (add%L0,%1,%0), low);
|
||
output_asm_insn (AS2 (adc%L0,%1,%0), high);
|
||
}
|
||
else
|
||
{
|
||
/* It's too late to ask for a scratch now - but this
|
||
will probably not happen too often. */
|
||
output_asm_insn (AS2 (add%L1,%2,%1), low);
|
||
output_asm_insn (AS2 (mov%L0,%1,%0), low);
|
||
output_asm_insn (AS2 (mov%L1,%2,%1), low);
|
||
output_asm_insn (AS2 (mov%L0,%2,%0), high);
|
||
output_asm_insn (AS2 (adc%L0,%1,%0), high);
|
||
output_asm_insn (AS2 (sub%L1,%0,%1), low);
|
||
output_asm_insn (AS1 (neg%L1,%1), low);
|
||
}
|
||
RET;
|
||
}
|
||
output_asm_insn (AS2 (mov%L1,%3,%1), xops);
|
||
output_asm_insn (AS2 (mov%L0,%2,%0), xops);
|
||
}
|
||
else
|
||
{
|
||
xops[4] = high[2];
|
||
xops[5] = low[2];
|
||
xops[6] = operands[3];
|
||
output_asm_insn (AS2 (mov%L6,%3,%6), xops);
|
||
output_asm_insn (AS2 (add%L6,%5,%6), xops);
|
||
output_asm_insn (AS2 (mov%L1,%6,%1), xops);
|
||
output_asm_insn (AS2 (mov%L6,%2,%6), xops);
|
||
output_asm_insn (AS2 (adc%L6,%4,%6), xops);
|
||
output_asm_insn (AS2 (mov%L0,%6,%0), xops);
|
||
RET;
|
||
}
|
||
}
|
||
|
||
output_asm_insn (AS2 (add%L0,%2,%0), low);
|
||
output_asm_insn (AS2 (adc%L0,%2,%0), high);
|
||
cc_status.value1 = high[0];
|
||
cc_status.flags = CC_NO_OVERFLOW;
|
||
RET;
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_insn "adddi3"
|
||
[(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o")
|
||
(plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o")
|
||
(match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o")))
|
||
(clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))]
|
||
""
|
||
"*
|
||
{
|
||
rtx low[3], high[3], xops[7], temp;
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
if (rtx_equal_p (operands[0], operands[2]))
|
||
{
|
||
temp = operands[1];
|
||
operands[1] = operands[2];
|
||
operands[2] = temp;
|
||
}
|
||
|
||
split_di (operands, 3, low, high);
|
||
if (!rtx_equal_p (operands[0], operands[1]))
|
||
{
|
||
xops[0] = high[0];
|
||
xops[1] = low[0];
|
||
xops[2] = high[1];
|
||
xops[3] = low[1];
|
||
|
||
if (GET_CODE (operands[0]) != MEM)
|
||
{
|
||
output_asm_insn (AS2 (mov%L1,%3,%1), xops);
|
||
output_asm_insn (AS2 (mov%L0,%2,%0), xops);
|
||
}
|
||
else
|
||
{
|
||
xops[4] = high[2];
|
||
xops[5] = low[2];
|
||
xops[6] = operands[3];
|
||
output_asm_insn (AS2 (mov%L6,%3,%6), xops);
|
||
output_asm_insn (AS2 (add%L6,%5,%6), xops);
|
||
output_asm_insn (AS2 (mov%L1,%6,%1), xops);
|
||
output_asm_insn (AS2 (mov%L6,%2,%6), xops);
|
||
output_asm_insn (AS2 (adc%L6,%4,%6), xops);
|
||
output_asm_insn (AS2 (mov%L0,%6,%0), xops);
|
||
RET;
|
||
}
|
||
}
|
||
|
||
cc_status.value1 = high[0];
|
||
cc_status.flags = CC_NO_OVERFLOW;
|
||
|
||
if (GET_CODE (operands[3]) == REG && GET_CODE (operands[2]) != REG)
|
||
{
|
||
xops[0] = high[0];
|
||
xops[1] = low[0];
|
||
xops[2] = high[2];
|
||
xops[3] = low[2];
|
||
xops[4] = operands[3];
|
||
|
||
output_asm_insn (AS2 (mov%L4,%3,%4), xops);
|
||
output_asm_insn (AS2 (add%L1,%4,%1), xops);
|
||
output_asm_insn (AS2 (mov%L4,%2,%4), xops);
|
||
output_asm_insn (AS2 (adc%L0,%4,%0), xops);
|
||
}
|
||
|
||
else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
|
||
{
|
||
output_asm_insn (AS2 (add%L0,%2,%0), low);
|
||
output_asm_insn (AS2 (adc%L0,%2,%0), high);
|
||
}
|
||
|
||
else
|
||
output_asm_insn (AS2 (add%L0,%2,%0), high);
|
||
|
||
RET;
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
;; On a 486, it is faster to do movl/addl than to do a single leal if
|
||
;; operands[1] and operands[2] are both registers.
|
||
|
||
(define_expand "addsi3"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "")
|
||
(plus:SI (match_operand:SI 1 "nonimmediate_operand" "")
|
||
(match_operand:SI 2 "general_operand" "")))]
|
||
""
|
||
"IX86_EXPAND_BINARY_OPERATOR (PLUS, SImode, operands);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm,r")
|
||
(plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,r")
|
||
(match_operand:SI 2 "general_operand" "rmi,ri,ri")))]
|
||
"ix86_binary_operator_ok (PLUS, SImode, operands)"
|
||
"*
|
||
{
|
||
if (REG_P (operands[0]) && REG_P (operands[1])
|
||
&& (REG_P (operands[2]) || CONSTANT_P (operands[2]))
|
||
&& REGNO (operands[0]) != REGNO (operands[1]))
|
||
{
|
||
if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
|
||
return AS2 (add%L0,%1,%0);
|
||
|
||
if (operands[2] == stack_pointer_rtx)
|
||
{
|
||
rtx temp;
|
||
|
||
temp = operands[1];
|
||
operands[1] = operands[2];
|
||
operands[2] = temp;
|
||
}
|
||
|
||
if (operands[2] != stack_pointer_rtx)
|
||
{
|
||
CC_STATUS_INIT;
|
||
operands[1] = SET_SRC (PATTERN (insn));
|
||
return AS2 (lea%L0,%a1,%0);
|
||
}
|
||
}
|
||
|
||
if (!rtx_equal_p (operands[0], operands[1]))
|
||
output_asm_insn (AS2 (mov%L0,%1,%0), operands);
|
||
|
||
if (operands[2] == const1_rtx)
|
||
return AS1 (inc%L0,%0);
|
||
|
||
if (operands[2] == constm1_rtx)
|
||
return AS1 (dec%L0,%0);
|
||
|
||
/* subl $-128,%ebx is smaller than addl $128,%ebx. */
|
||
if (GET_CODE (operands[2]) == CONST_INT
|
||
&& INTVAL (operands[2]) == 128)
|
||
{
|
||
/* This doesn't compute the carry bit in the same way
|
||
* as add%L0, but we use inc and dec above and they
|
||
* don't set the carry bit at all. If inc/dec don't need
|
||
* a CC_STATUS_INIT, this doesn't either... */
|
||
operands[2] = GEN_INT (-128);
|
||
return AS2 (sub%L0,%2,%0);
|
||
}
|
||
|
||
return AS2 (add%L0,%2,%0);
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
;; addsi3 is faster, so put this after.
|
||
|
||
(define_insn "movsi_lea"
|
||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||
(match_operand:QI 1 "address_operand" "p"))]
|
||
""
|
||
"*
|
||
{
|
||
/* Adding a constant to a register is faster with an add. */
|
||
/* ??? can this ever happen? */
|
||
if (GET_CODE (operands[1]) == PLUS
|
||
&& GET_CODE (XEXP (operands[1], 1)) == CONST_INT
|
||
&& rtx_equal_p (operands[0], XEXP (operands[1], 0)))
|
||
{
|
||
operands[1] = XEXP (operands[1], 1);
|
||
|
||
if (operands[1] == const1_rtx)
|
||
return AS1 (inc%L0,%0);
|
||
|
||
if (operands[1] == constm1_rtx)
|
||
return AS1 (dec%L0,%0);
|
||
|
||
return AS2 (add%L0,%1,%0);
|
||
}
|
||
|
||
CC_STATUS_INIT;
|
||
return AS2 (lea%L0,%a1,%0);
|
||
}"
|
||
[(set_attr "type" "lea")])
|
||
|
||
;; ??? `lea' here, for three operand add? If leaw is used, only %bx,
|
||
;; %si and %di can appear in SET_SRC, and output_asm_insn might not be
|
||
;; able to handle the operand. But leal always works?
|
||
|
||
(define_expand "addhi3"
|
||
[(set (match_operand:HI 0 "general_operand" "")
|
||
(plus:HI (match_operand:HI 1 "nonimmediate_operand" "")
|
||
(match_operand:HI 2 "general_operand" "")))]
|
||
""
|
||
"IX86_EXPAND_BINARY_OPERATOR (PLUS, HImode, operands);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,?r")
|
||
(plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,r")
|
||
(match_operand:HI 2 "general_operand" "ri,rm,ri")))]
|
||
"ix86_binary_operator_ok (PLUS, HImode, operands)"
|
||
"*
|
||
{
|
||
if (REG_P (operands[0]) && REG_P (operands[1])
|
||
&& (REG_P (operands[2]) || CONSTANT_P (operands[2]))
|
||
&& REGNO (operands[0]) != REGNO (operands[1]))
|
||
{
|
||
if (operands[2] == stack_pointer_rtx)
|
||
abort ();
|
||
|
||
CC_STATUS_INIT;
|
||
operands[1]
|
||
= gen_rtx_PLUS (SImode,
|
||
gen_rtx_REG (SImode, REGNO (operands[1])),
|
||
(! REG_P (operands[2])
|
||
? operands[2]
|
||
: gen_rtx_REG (SImode, REGNO (operands[2]))));
|
||
operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
|
||
return AS2 (lea%L0,%a1,%0);
|
||
}
|
||
|
||
/* ??? what about offsettable memory references? */
|
||
if (!TARGET_PENTIUMPRO /* partial stalls are just too painful to risk. */
|
||
&& QI_REG_P (operands[0])
|
||
&& GET_CODE (operands[2]) == CONST_INT
|
||
&& (INTVAL (operands[2]) & 0xff) == 0
|
||
&& i386_cc_probably_useless_p (insn))
|
||
{
|
||
int byteval = (INTVAL (operands[2]) >> 8) & 0xff;
|
||
CC_STATUS_INIT;
|
||
|
||
if (byteval == 1)
|
||
return AS1 (inc%B0,%h0);
|
||
else if (byteval == 255)
|
||
return AS1 (dec%B0,%h0);
|
||
|
||
operands[2] = GEN_INT (byteval);
|
||
return AS2 (add%B0,%2,%h0);
|
||
}
|
||
|
||
/* Use a 32-bit operation when possible, to avoid the prefix penalty. */
|
||
if (REG_P (operands[0])
|
||
&& i386_aligned_p (operands[2])
|
||
&& i386_cc_probably_useless_p (insn))
|
||
{
|
||
CC_STATUS_INIT;
|
||
|
||
if (GET_CODE (operands[2]) == CONST_INT)
|
||
{
|
||
HOST_WIDE_INT intval = 0xffff & INTVAL (operands[2]);
|
||
|
||
if (intval == 1)
|
||
return AS1 (inc%L0,%k0);
|
||
|
||
if (intval == 0xffff)
|
||
return AS1 (dec%L0,%k0);
|
||
|
||
operands[2] = i386_sext16_if_const (operands[2]);
|
||
}
|
||
return AS2 (add%L0,%k2,%k0);
|
||
}
|
||
|
||
if (operands[2] == const1_rtx)
|
||
return AS1 (inc%W0,%0);
|
||
|
||
if (operands[2] == constm1_rtx
|
||
|| (GET_CODE (operands[2]) == CONST_INT
|
||
&& INTVAL (operands[2]) == 65535))
|
||
return AS1 (dec%W0,%0);
|
||
|
||
return AS2 (add%W0,%2,%0);
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_expand "addqi3"
|
||
[(set (match_operand:QI 0 "general_operand" "")
|
||
(plus:QI (match_operand:QI 1 "general_operand" "")
|
||
(match_operand:QI 2 "general_operand" "")))]
|
||
""
|
||
"IX86_EXPAND_BINARY_OPERATOR (PLUS, QImode, operands);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,?q")
|
||
(plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,q")
|
||
(match_operand:QI 2 "general_operand" "qn,qmn,qn")))]
|
||
"ix86_binary_operator_ok (PLUS, QImode, operands)"
|
||
"*
|
||
{
|
||
if (REG_P (operands[0]) && REG_P (operands[1])
|
||
&& (REG_P (operands[2]) || CONSTANT_P (operands[2]))
|
||
&& (REGNO (operands[0]) != REGNO (operands[1])
|
||
|| NON_QI_REG_P (operands[1])
|
||
|| (REG_P (operands[2]) && NON_QI_REG_P (operands[2]))))
|
||
{
|
||
if (operands[2] == stack_pointer_rtx)
|
||
abort ();
|
||
|
||
CC_STATUS_INIT;
|
||
operands[1]
|
||
= gen_rtx_PLUS (SImode,
|
||
gen_rtx_REG (SImode, REGNO (operands[1])),
|
||
(! REG_P (operands[2])
|
||
? operands[2]
|
||
: gen_rtx_REG (SImode, REGNO (operands[2]))));
|
||
operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
|
||
return AS2 (lea%L0,%a1,%0);
|
||
}
|
||
if (operands[2] == const1_rtx)
|
||
return AS1 (inc%B0,%0);
|
||
|
||
if (operands[2] == constm1_rtx
|
||
|| (GET_CODE (operands[2]) == CONST_INT
|
||
&& INTVAL (operands[2]) == 255))
|
||
return AS1 (dec%B0,%0);
|
||
|
||
return AS2 (add%B0,%2,%0);
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
;Lennart Augustsson <augustss@cs.chalmers.se>
|
||
;says this pattern just makes slower code:
|
||
; pushl %ebp
|
||
; addl $-80,(%esp)
|
||
;instead of
|
||
; leal -80(%ebp),%eax
|
||
; pushl %eax
|
||
;
|
||
;(define_insn ""
|
||
; [(set (match_operand:SI 0 "push_operand" "=<")
|
||
; (plus:SI (match_operand:SI 1 "register_operand" "%r")
|
||
; (match_operand:SI 2 "nonmemory_operand" "ri")))]
|
||
; ""
|
||
; "*
|
||
;{
|
||
; rtx xops[4];
|
||
; xops[0] = operands[0];
|
||
; xops[1] = operands[1];
|
||
; xops[2] = operands[2];
|
||
; xops[3] = gen_rtx_MEM (SImode, stack_pointer_rtx);
|
||
; output_asm_insn (\"push%z1 %1\", xops);
|
||
; output_asm_insn (AS2 (add%z3,%2,%3), xops);
|
||
; RET;
|
||
;}")
|
||
|
||
;; The patterns that match these are at the end of this file.
|
||
|
||
(define_expand "addxf3"
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(plus:XF (match_operand:XF 1 "register_operand" "")
|
||
(match_operand:XF 2 "register_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "adddf3"
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(plus:DF (match_operand:DF 1 "nonimmediate_operand" "")
|
||
(match_operand:DF 2 "nonimmediate_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "addsf3"
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(plus:SF (match_operand:SF 1 "nonimmediate_operand" "")
|
||
(match_operand:SF 2 "nonimmediate_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
;;- subtract instructions
|
||
|
||
(define_insn "subsidi3"
|
||
[(set (match_operand:DI 0 "general_operand" "=&r,&ro,&r,!&r,o,o,!o")
|
||
(minus:DI (match_operand:DI 1 "general_operand" "0iF,0,roiF,roiF,riF,o,o")
|
||
(zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,o,ri,i,r"))))
|
||
(clobber (match_scratch:SI 3 "=X,X,X,X,X,&r,&r"))]
|
||
""
|
||
"*
|
||
{
|
||
rtx low[3], high[3], xops[7];
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
split_di (operands, 2, low, high);
|
||
high[2] = const0_rtx;
|
||
low[2] = operands[2];
|
||
|
||
if (!rtx_equal_p (operands[0], operands[1]))
|
||
{
|
||
xops[0] = high[0];
|
||
xops[1] = low[0];
|
||
xops[2] = high[1];
|
||
xops[3] = low[1];
|
||
|
||
if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
|
||
{
|
||
output_asm_insn (AS2 (mov%L1,%3,%1), xops);
|
||
output_asm_insn (AS2 (mov%L0,%2,%0), xops);
|
||
}
|
||
else
|
||
{
|
||
xops[4] = high[2];
|
||
xops[5] = low[2];
|
||
xops[6] = operands[3];
|
||
output_asm_insn (AS2 (mov%L6,%3,%6), xops);
|
||
output_asm_insn (AS2 (sub%L6,%5,%6), xops);
|
||
output_asm_insn (AS2 (mov%L1,%6,%1), xops);
|
||
output_asm_insn (AS2 (mov%L6,%2,%6), xops);
|
||
output_asm_insn (AS2 (sbb%L6,%4,%6), xops);
|
||
output_asm_insn (AS2 (mov%L0,%6,%0), xops);
|
||
RET;
|
||
}
|
||
}
|
||
|
||
output_asm_insn (AS2 (sub%L0,%2,%0), low);
|
||
output_asm_insn (AS2 (sbb%L0,%2,%0), high);
|
||
cc_status.value1 = high[0];
|
||
cc_status.flags = CC_NO_OVERFLOW;
|
||
|
||
RET;
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_insn "subdi3"
|
||
[(set (match_operand:DI 0 "general_operand" "=&r,&ro,o,o,!&r,!o")
|
||
(minus:DI (match_operand:DI 1 "general_operand" "0,0,0iF,or,roiF,roiF")
|
||
(match_operand:DI 2 "general_operand" "or,riF,or,iF,roiF,roiF")))
|
||
(clobber (match_scratch:SI 3 "=X,X,&r,&r,X,&r"))]
|
||
""
|
||
"*
|
||
{
|
||
rtx low[3], high[3], xops[7];
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
split_di (operands, 3, low, high);
|
||
|
||
if (!rtx_equal_p (operands[0], operands[1]))
|
||
{
|
||
xops[0] = high[0];
|
||
xops[1] = low[0];
|
||
xops[2] = high[1];
|
||
xops[3] = low[1];
|
||
|
||
if (GET_CODE (operands[0]) != MEM)
|
||
{
|
||
output_asm_insn (AS2 (mov%L1,%3,%1), xops);
|
||
output_asm_insn (AS2 (mov%L0,%2,%0), xops);
|
||
}
|
||
else
|
||
{
|
||
xops[4] = high[2];
|
||
xops[5] = low[2];
|
||
xops[6] = operands[3];
|
||
output_asm_insn (AS2 (mov%L6,%3,%6), xops);
|
||
output_asm_insn (AS2 (sub%L6,%5,%6), xops);
|
||
output_asm_insn (AS2 (mov%L1,%6,%1), xops);
|
||
output_asm_insn (AS2 (mov%L6,%2,%6), xops);
|
||
output_asm_insn (AS2 (sbb%L6,%4,%6), xops);
|
||
output_asm_insn (AS2 (mov%L0,%6,%0), xops);
|
||
RET;
|
||
}
|
||
}
|
||
|
||
cc_status.value1 = high[0];
|
||
cc_status.flags = CC_NO_OVERFLOW;
|
||
|
||
if (GET_CODE (operands[3]) == REG)
|
||
{
|
||
xops[0] = high[0];
|
||
xops[1] = low[0];
|
||
xops[2] = high[2];
|
||
xops[3] = low[2];
|
||
xops[4] = operands[3];
|
||
|
||
output_asm_insn (AS2 (mov%L4,%3,%4), xops);
|
||
output_asm_insn (AS2 (sub%L1,%4,%1), xops);
|
||
output_asm_insn (AS2 (mov%L4,%2,%4), xops);
|
||
output_asm_insn (AS2 (sbb%L0,%4,%0), xops);
|
||
}
|
||
|
||
else if (GET_CODE (low[2]) != CONST_INT || INTVAL (low[2]) != 0)
|
||
{
|
||
output_asm_insn (AS2 (sub%L0,%2,%0), low);
|
||
output_asm_insn (AS2 (sbb%L0,%2,%0), high);
|
||
}
|
||
|
||
else
|
||
output_asm_insn (AS2 (sub%L0,%2,%0), high);
|
||
|
||
|
||
RET;
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_expand "subsi3"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "")
|
||
(minus:SI (match_operand:SI 1 "nonimmediate_operand" "")
|
||
(match_operand:SI 2 "general_operand" "")))]
|
||
""
|
||
"IX86_EXPAND_BINARY_OPERATOR (MINUS, SImode, operands);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
|
||
(minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
|
||
(match_operand:SI 2 "general_operand" "ri,rm")))]
|
||
"ix86_binary_operator_ok (MINUS, SImode, operands)"
|
||
"* return AS2 (sub%L0,%2,%0);"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_expand "subhi3"
|
||
[(set (match_operand:HI 0 "general_operand" "")
|
||
(minus:HI (match_operand:HI 1 "nonimmediate_operand" "")
|
||
(match_operand:HI 2 "general_operand" "")))]
|
||
""
|
||
"IX86_EXPAND_BINARY_OPERATOR (MINUS, HImode, operands);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
|
||
(minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
|
||
(match_operand:HI 2 "general_operand" "ri,rm")))]
|
||
"ix86_binary_operator_ok (MINUS, HImode, operands)"
|
||
"*
|
||
{
|
||
if (REG_P (operands[0])
|
||
&& i386_aligned_p (operands[2])
|
||
&& i386_cc_probably_useless_p (insn))
|
||
{
|
||
CC_STATUS_INIT;
|
||
operands[2] = i386_sext16_if_const (operands[2]);
|
||
return AS2 (sub%L0,%k2,%k0);
|
||
}
|
||
return AS2 (sub%W0,%2,%0);
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_expand "subqi3"
|
||
[(set (match_operand:QI 0 "general_operand" "")
|
||
(minus:QI (match_operand:QI 1 "general_operand" "")
|
||
(match_operand:QI 2 "general_operand" "")))]
|
||
""
|
||
"IX86_EXPAND_BINARY_OPERATOR (MINUS, QImode, operands);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
|
||
(minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
|
||
(match_operand:QI 2 "general_operand" "qn,qmn")))]
|
||
"ix86_binary_operator_ok (MINUS, QImode, operands)"
|
||
"* return AS2 (sub%B0,%2,%0);"
|
||
[(set_attr "type" "binary")])
|
||
|
||
;; The patterns that match these are at the end of this file.
|
||
|
||
(define_expand "subxf3"
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(minus:XF (match_operand:XF 1 "register_operand" "")
|
||
(match_operand:XF 2 "register_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "subdf3"
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(minus:DF (match_operand:DF 1 "nonimmediate_operand" "")
|
||
(match_operand:DF 2 "nonimmediate_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "subsf3"
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(minus:SF (match_operand:SF 1 "nonimmediate_operand" "")
|
||
(match_operand:SF 2 "nonimmediate_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
;;- multiply instructions
|
||
|
||
;(define_insn "mulqi3"
|
||
; [(set (match_operand:QI 0 "register_operand" "=a")
|
||
; (mult:QI (match_operand:QI 1 "register_operand" "%0")
|
||
; (match_operand:QI 2 "nonimmediate_operand" "qm")))]
|
||
; ""
|
||
; "imul%B0 %2,%0")
|
||
|
||
(define_insn "mulhi3"
|
||
[(set (match_operand:HI 0 "register_operand" "=r,r")
|
||
(mult:HI (match_operand:HI 1 "nonimmediate_operand" "%0,rm")
|
||
(match_operand:HI 2 "general_operand" "g,i")))]
|
||
""
|
||
"*
|
||
{
|
||
if (GET_CODE (operands[1]) == REG
|
||
&& REGNO (operands[1]) == REGNO (operands[0])
|
||
&& (GET_CODE (operands[2]) == MEM || GET_CODE (operands[2]) == REG))
|
||
/* Assembler has weird restrictions. */
|
||
return AS2 (imul%W0,%2,%0);
|
||
return AS3 (imul%W0,%2,%1,%0);
|
||
}"
|
||
[(set_attr "type" "imul")])
|
||
|
||
(define_insn "mulsi3"
|
||
[(set (match_operand:SI 0 "register_operand" "=r,r")
|
||
(mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,rm")
|
||
(match_operand:SI 2 "general_operand" "g,i")))]
|
||
""
|
||
"*
|
||
{
|
||
if (GET_CODE (operands[1]) == REG
|
||
&& REGNO (operands[1]) == REGNO (operands[0])
|
||
&& (GET_CODE (operands[2]) == MEM || GET_CODE (operands[2]) == REG))
|
||
/* Assembler has weird restrictions. */
|
||
return AS2 (imul%L0,%2,%0);
|
||
return AS3 (imul%L0,%2,%1,%0);
|
||
}"
|
||
[(set_attr "type" "imul")])
|
||
|
||
(define_insn "umulqihi3"
|
||
[(set (match_operand:HI 0 "register_operand" "=a")
|
||
(mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
|
||
(zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))]
|
||
""
|
||
"mul%B0 %2"
|
||
[(set_attr "type" "imul")])
|
||
|
||
(define_insn "mulqihi3"
|
||
[(set (match_operand:HI 0 "register_operand" "=a")
|
||
(mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
|
||
(sign_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))]
|
||
""
|
||
"imul%B0 %2"
|
||
[(set_attr "type" "imul")])
|
||
|
||
(define_insn "umulsidi3"
|
||
[(set (match_operand:DI 0 "register_operand" "=A")
|
||
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
|
||
(zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))]
|
||
"TARGET_WIDE_MULTIPLY"
|
||
"mul%L0 %2"
|
||
[(set_attr "type" "imul")])
|
||
|
||
(define_insn "mulsidi3"
|
||
[(set (match_operand:DI 0 "register_operand" "=A")
|
||
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
|
||
(sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))]
|
||
"TARGET_WIDE_MULTIPLY"
|
||
"imul%L0 %2"
|
||
[(set_attr "type" "imul")])
|
||
|
||
(define_insn "umulsi3_highpart"
|
||
[(set (match_operand:SI 0 "register_operand" "=d")
|
||
(truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%a"))
|
||
(zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))
|
||
(const_int 32))))
|
||
(clobber (match_scratch:SI 3 "=a"))]
|
||
"TARGET_WIDE_MULTIPLY"
|
||
"mul%L0 %2"
|
||
[(set_attr "type" "imul")])
|
||
|
||
(define_insn "smulsi3_highpart"
|
||
[(set (match_operand:SI 0 "register_operand" "=d")
|
||
(truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%a"))
|
||
(sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))
|
||
(const_int 32))))
|
||
(clobber (match_scratch:SI 3 "=a"))]
|
||
"TARGET_WIDE_MULTIPLY"
|
||
"imul%L0 %2"
|
||
[(set_attr "type" "imul")])
|
||
|
||
;; The patterns that match these are at the end of this file.
|
||
|
||
(define_expand "mulxf3"
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(mult:XF (match_operand:XF 1 "register_operand" "")
|
||
(match_operand:XF 2 "register_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "muldf3"
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(mult:DF (match_operand:DF 1 "register_operand" "")
|
||
(match_operand:DF 2 "nonimmediate_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "mulsf3"
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(mult:SF (match_operand:SF 1 "register_operand" "")
|
||
(match_operand:SF 2 "nonimmediate_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
;;- divide instructions
|
||
|
||
(define_insn "divqi3"
|
||
[(set (match_operand:QI 0 "register_operand" "=a")
|
||
(div:QI (match_operand:HI 1 "register_operand" "0")
|
||
(match_operand:QI 2 "nonimmediate_operand" "qm")))]
|
||
""
|
||
"idiv%B0 %2")
|
||
|
||
(define_insn "udivqi3"
|
||
[(set (match_operand:QI 0 "register_operand" "=a")
|
||
(udiv:QI (match_operand:HI 1 "register_operand" "0")
|
||
(match_operand:QI 2 "nonimmediate_operand" "qm")))]
|
||
""
|
||
"div%B0 %2"
|
||
[(set_attr "type" "idiv")])
|
||
|
||
;; The patterns that match these are at the end of this file.
|
||
|
||
(define_expand "divxf3"
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(div:XF (match_operand:XF 1 "register_operand" "")
|
||
(match_operand:XF 2 "register_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "divdf3"
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(div:DF (match_operand:DF 1 "register_operand" "")
|
||
(match_operand:DF 2 "nonimmediate_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
(define_expand "divsf3"
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(div:SF (match_operand:SF 1 "register_operand" "")
|
||
(match_operand:SF 2 "nonimmediate_operand" "")))]
|
||
"TARGET_80387"
|
||
"")
|
||
|
||
;; Remainder instructions.
|
||
|
||
(define_insn "divmodsi4"
|
||
[(set (match_operand:SI 0 "register_operand" "=a")
|
||
(div:SI (match_operand:SI 1 "register_operand" "0")
|
||
(match_operand:SI 2 "nonimmediate_operand" "rm")))
|
||
(set (match_operand:SI 3 "register_operand" "=&d")
|
||
(mod:SI (match_dup 1) (match_dup 2)))]
|
||
""
|
||
"*
|
||
{
|
||
#ifdef INTEL_SYNTAX
|
||
output_asm_insn (\"cdq\", operands);
|
||
#else
|
||
output_asm_insn (\"cltd\", operands);
|
||
#endif
|
||
return AS1 (idiv%L0,%2);
|
||
}"
|
||
[(set_attr "type" "idiv")])
|
||
|
||
(define_insn "divmodhi4"
|
||
[(set (match_operand:HI 0 "register_operand" "=a")
|
||
(div:HI (match_operand:HI 1 "register_operand" "0")
|
||
(match_operand:HI 2 "nonimmediate_operand" "rm")))
|
||
(set (match_operand:HI 3 "register_operand" "=&d")
|
||
(mod:HI (match_dup 1) (match_dup 2)))]
|
||
""
|
||
"cwtd\;idiv%W0 %2"
|
||
[(set_attr "type" "idiv")])
|
||
|
||
;; ??? Can we make gcc zero extend operand[0]?
|
||
(define_insn "udivmodsi4"
|
||
[(set (match_operand:SI 0 "register_operand" "=a")
|
||
(udiv:SI (match_operand:SI 1 "register_operand" "0")
|
||
(match_operand:SI 2 "nonimmediate_operand" "rm")))
|
||
(set (match_operand:SI 3 "register_operand" "=&d")
|
||
(umod:SI (match_dup 1) (match_dup 2)))]
|
||
""
|
||
"*
|
||
{
|
||
output_asm_insn (AS2 (xor%L3,%3,%3), operands);
|
||
return AS1 (div%L0,%2);
|
||
}"
|
||
[(set_attr "type" "idiv")])
|
||
|
||
;; ??? Can we make gcc zero extend operand[0]?
|
||
(define_insn "udivmodhi4"
|
||
[(set (match_operand:HI 0 "register_operand" "=a")
|
||
(udiv:HI (match_operand:HI 1 "register_operand" "0")
|
||
(match_operand:HI 2 "nonimmediate_operand" "rm")))
|
||
(set (match_operand:HI 3 "register_operand" "=&d")
|
||
(umod:HI (match_dup 1) (match_dup 2)))]
|
||
""
|
||
"*
|
||
{
|
||
output_asm_insn (AS2 (xor%W0,%3,%3), operands);
|
||
return AS1 (div%W0,%2);
|
||
}"
|
||
[(set_attr "type" "idiv")])
|
||
|
||
/*
|
||
;;this should be a valid double division which we may want to add
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "register_operand" "=a")
|
||
(udiv:DI (match_operand:DI 1 "register_operand" "a")
|
||
(match_operand:SI 2 "nonimmediate_operand" "rm")))
|
||
(set (match_operand:SI 3 "register_operand" "=d")
|
||
(umod:SI (match_dup 1) (match_dup 2)))]
|
||
""
|
||
"div%L0 %2,%0"
|
||
[(set_attr "type" "idiv")])
|
||
*/
|
||
|
||
;;- and instructions
|
||
|
||
;; On i386,
|
||
;; movzbl %bl,%ebx
|
||
;; is faster than
|
||
;; andl $255,%ebx
|
||
;;
|
||
;; but if the reg is %eax, then the "andl" is faster.
|
||
;;
|
||
;; On i486, the "andl" is always faster than the "movzbl".
|
||
;;
|
||
;; On both i386 and i486, a three operand AND is as fast with movzbl or
|
||
;; movzwl as with andl, if operands[0] != operands[1].
|
||
|
||
;; The `r' in `rm' for operand 3 looks redundant, but it causes
|
||
;; optional reloads to be generated if op 3 is a pseudo in a stack slot.
|
||
|
||
(define_insn "andsi3"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
|
||
(and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
|
||
(match_operand:SI 2 "general_operand" "ri,rm")))]
|
||
""
|
||
"*
|
||
{
|
||
HOST_WIDE_INT intval;
|
||
if (!rtx_equal_p (operands[0], operands[1])
|
||
&& rtx_equal_p (operands[0], operands[2]))
|
||
{
|
||
rtx tmp;
|
||
tmp = operands[1];
|
||
operands[1] = operands[2];
|
||
operands[2] = tmp;
|
||
}
|
||
switch (GET_CODE (operands[2]))
|
||
{
|
||
case CONST_INT:
|
||
if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
|
||
break;
|
||
intval = INTVAL (operands[2]);
|
||
/* zero-extend 16->32? */
|
||
if (intval == 0xffff && REG_P (operands[0])
|
||
&& (! REG_P (operands[1])
|
||
|| REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
|
||
&& (!TARGET_ZERO_EXTEND_WITH_AND || ! rtx_equal_p (operands[0], operands[1])))
|
||
{
|
||
/* ??? tege: Should forget CC_STATUS only if we clobber a
|
||
remembered operand. Fix that later. */
|
||
CC_STATUS_INIT;
|
||
#ifdef INTEL_SYNTAX
|
||
return AS2 (movzx,%w1,%0);
|
||
#else
|
||
return AS2 (movz%W0%L0,%w1,%0);
|
||
#endif
|
||
}
|
||
|
||
/* zero extend 8->32? */
|
||
if (intval == 0xff && REG_P (operands[0])
|
||
&& !(REG_P (operands[1]) && NON_QI_REG_P (operands[1]))
|
||
&& (! REG_P (operands[1])
|
||
|| REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
|
||
&& (!TARGET_ZERO_EXTEND_WITH_AND || ! rtx_equal_p (operands[0], operands[1])))
|
||
{
|
||
/* ??? tege: Should forget CC_STATUS only if we clobber a
|
||
remembered operand. Fix that later. */
|
||
CC_STATUS_INIT;
|
||
#ifdef INTEL_SYNTAX
|
||
return AS2 (movzx,%b1,%0);
|
||
#else
|
||
return AS2 (movz%B0%L0,%b1,%0);
|
||
#endif
|
||
}
|
||
|
||
/* Check partial bytes.. non-QI-regs are not available */
|
||
if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
|
||
break;
|
||
|
||
/* only low byte has zero bits? */
|
||
if (~(intval | 0xff) == 0)
|
||
{
|
||
intval &= 0xff;
|
||
if (REG_P (operands[0]))
|
||
{
|
||
if (intval == 0)
|
||
{
|
||
CC_STATUS_INIT;
|
||
return AS2 (xor%B0,%b0,%b0);
|
||
}
|
||
|
||
/* we're better off with the 32-bit version if reg != EAX */
|
||
/* the value is sign-extended in 8 bits */
|
||
if (REGNO (operands[0]) != 0 && (intval & 0x80))
|
||
break;
|
||
}
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
operands[2] = GEN_INT (intval);
|
||
|
||
if (intval == 0)
|
||
return AS2 (mov%B0,%2,%b0);
|
||
|
||
return AS2 (and%B0,%2,%b0);
|
||
}
|
||
|
||
/* only second byte has zero? */
|
||
if (~(intval | 0xff00) == 0)
|
||
{
|
||
CC_STATUS_INIT;
|
||
|
||
intval = (intval >> 8) & 0xff;
|
||
operands[2] = GEN_INT (intval);
|
||
if (intval == 0)
|
||
{
|
||
if (REG_P (operands[0]))
|
||
return AS2 (xor%B0,%h0,%h0);
|
||
operands[0] = adj_offsettable_operand (operands[0], 1);
|
||
return AS2 (mov%B0,%2,%b0);
|
||
}
|
||
|
||
if (REG_P (operands[0]))
|
||
return AS2 (and%B0,%2,%h0);
|
||
|
||
operands[0] = adj_offsettable_operand (operands[0], 1);
|
||
return AS2 (and%B0,%2,%b0);
|
||
}
|
||
|
||
if (REG_P (operands[0]))
|
||
break;
|
||
|
||
/* third byte has zero bits? */
|
||
if (~(intval | 0xff0000) == 0)
|
||
{
|
||
intval = (intval >> 16) & 0xff;
|
||
operands[0] = adj_offsettable_operand (operands[0], 2);
|
||
byte_and_operation:
|
||
CC_STATUS_INIT;
|
||
operands[2] = GEN_INT (intval);
|
||
if (intval == 0)
|
||
return AS2 (mov%B0,%2,%b0);
|
||
return AS2 (and%B0,%2,%b0);
|
||
}
|
||
|
||
/* fourth byte has zero bits? */
|
||
if (~(intval | 0xff000000) == 0)
|
||
{
|
||
intval = (intval >> 24) & 0xff;
|
||
operands[0] = adj_offsettable_operand (operands[0], 3);
|
||
goto byte_and_operation;
|
||
}
|
||
|
||
/* Low word is zero? */
|
||
if (intval == 0xffff0000)
|
||
{
|
||
word_zero_and_operation:
|
||
CC_STATUS_INIT;
|
||
operands[2] = const0_rtx;
|
||
return AS2 (mov%W0,%2,%w0);
|
||
}
|
||
|
||
/* High word is zero? */
|
||
if (intval == 0x0000ffff)
|
||
{
|
||
operands[0] = adj_offsettable_operand (operands[0], 2);
|
||
goto word_zero_and_operation;
|
||
}
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return AS2 (and%L0,%2,%0);
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_insn "andhi3"
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
|
||
(and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
|
||
(match_operand:HI 2 "general_operand" "ri,rm")))]
|
||
""
|
||
"*
|
||
{
|
||
if (GET_CODE (operands[2]) == CONST_INT
|
||
&& ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
|
||
{
|
||
/* Can we ignore the upper byte? */
|
||
if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
|
||
&& (INTVAL (operands[2]) & 0xff00) == 0xff00)
|
||
{
|
||
CC_STATUS_INIT;
|
||
|
||
if ((INTVAL (operands[2]) & 0xff) == 0)
|
||
{
|
||
operands[2] = const0_rtx;
|
||
return AS2 (mov%B0,%2,%b0);
|
||
}
|
||
|
||
operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff);
|
||
return AS2 (and%B0,%2,%b0);
|
||
}
|
||
|
||
/* Can we ignore the lower byte? */
|
||
/* ??? what about offsettable memory references? */
|
||
if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & 0xff) == 0xff)
|
||
{
|
||
CC_STATUS_INIT;
|
||
|
||
if ((INTVAL (operands[2]) & 0xff00) == 0)
|
||
{
|
||
operands[2] = const0_rtx;
|
||
return AS2 (mov%B0,%2,%h0);
|
||
}
|
||
|
||
operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
|
||
return AS2 (and%B0,%2,%h0);
|
||
}
|
||
|
||
/* use 32-bit ops on registers when there are no sign issues.. */
|
||
if (REG_P (operands[0]))
|
||
{
|
||
if (!(INTVAL (operands[2]) & ~0x7fff))
|
||
return AS2 (and%L0,%2,%k0);
|
||
}
|
||
}
|
||
|
||
if (REG_P (operands[0])
|
||
&& i386_aligned_p (operands[2]))
|
||
{
|
||
CC_STATUS_INIT;
|
||
/* If op[2] is constant, we should zero-extend it and */
|
||
/* make a note that op[0] has been zero-extended, so */
|
||
/* that we could use 32-bit ops on it forthwith, but */
|
||
/* there is no such reg-note available. Instead we do */
|
||
/* a sign extension as that can result in shorter asm */
|
||
operands[2] = i386_sext16_if_const (operands[2]);
|
||
return AS2 (and%L0,%k2,%k0);
|
||
}
|
||
|
||
/* Use a 32-bit word with the upper bits set, invalidate CC */
|
||
if (GET_CODE (operands[2]) == CONST_INT
|
||
&& i386_aligned_p (operands[0]))
|
||
{
|
||
HOST_WIDE_INT val = INTVAL (operands[2]);
|
||
CC_STATUS_INIT;
|
||
val |= ~0xffff;
|
||
if (val != INTVAL (operands[2]))
|
||
operands[2] = GEN_INT (val);
|
||
return AS2 (and%L0,%k2,%k0);
|
||
}
|
||
|
||
return AS2 (and%W0,%2,%0);
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_insn "andqi3"
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
|
||
(and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
|
||
(match_operand:QI 2 "general_operand" "qn,qmn")))]
|
||
""
|
||
"* return AS2 (and%B0,%2,%0);"
|
||
[(set_attr "type" "binary")])
|
||
|
||
/* I am nervous about these two.. add them later..
|
||
;I presume this means that we have something in say op0= eax which is small
|
||
;and we want to and it with memory so we can do this by just an
|
||
;andb m,%al and have success.
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "general_operand" "=r")
|
||
(and:SI (zero_extend:SI
|
||
(match_operand:HI 1 "nonimmediate_operand" "rm"))
|
||
(match_operand:SI 2 "general_operand" "0")))]
|
||
"GET_CODE (operands[2]) == CONST_INT
|
||
&& (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (HImode))"
|
||
"and%W0 %1,%0")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "register_operand" "=q")
|
||
(and:SI
|
||
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm"))
|
||
(match_operand:SI 2 "register_operand" "0")))]
|
||
"GET_CODE (operands[2]) == CONST_INT
|
||
&& (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))"
|
||
"and%L0 %1,%0")
|
||
|
||
*/
|
||
|
||
;;- Bit set (inclusive or) instructions
|
||
|
||
;; This optimizes known byte-wide operations to memory, and in some cases
|
||
;; to QI registers.. Note that we don't want to use the QI registers too
|
||
;; aggressively, because often the 32-bit register instruction is the same
|
||
;; size, and likely to be faster on PentiumPro.
|
||
(define_insn "iorsi3"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
|
||
(ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
|
||
(match_operand:SI 2 "general_operand" "ri,rm")))]
|
||
""
|
||
"*
|
||
{
|
||
HOST_WIDE_INT intval;
|
||
switch (GET_CODE (operands[2]))
|
||
{
|
||
case CONST_INT:
|
||
|
||
if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
|
||
break;
|
||
|
||
/* don't try to optimize volatile accesses */
|
||
if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
|
||
break;
|
||
|
||
intval = INTVAL (operands[2]);
|
||
if ((intval & ~0xff) == 0)
|
||
{
|
||
if (REG_P (operands[0]))
|
||
{
|
||
/* Do low byte access only for %eax or when high bit is set */
|
||
if (REGNO (operands[0]) != 0 && !(intval & 0x80))
|
||
break;
|
||
}
|
||
|
||
byte_or_operation:
|
||
CC_STATUS_INIT;
|
||
|
||
if (intval != INTVAL (operands[2]))
|
||
operands[2] = GEN_INT (intval);
|
||
|
||
if (intval == 0xff)
|
||
return AS2 (mov%B0,%2,%b0);
|
||
|
||
return AS2 (or%B0,%2,%b0);
|
||
}
|
||
|
||
/* second byte? */
|
||
if ((intval & ~0xff00) == 0)
|
||
{
|
||
intval >>= 8;
|
||
|
||
if (REG_P (operands[0]))
|
||
{
|
||
CC_STATUS_INIT;
|
||
operands[2] = GEN_INT (intval);
|
||
if (intval == 0xff)
|
||
return AS2 (mov%B0,%2,%h0);
|
||
|
||
return AS2 (or%B0,%2,%h0);
|
||
}
|
||
|
||
operands[0] = adj_offsettable_operand (operands[0], 1);
|
||
goto byte_or_operation;
|
||
}
|
||
|
||
if (REG_P (operands[0]))
|
||
break;
|
||
|
||
/* third byte? */
|
||
if ((intval & ~0xff0000) == 0)
|
||
{
|
||
intval >>= 16;
|
||
operands[0] = adj_offsettable_operand (operands[0], 2);
|
||
goto byte_or_operation;
|
||
}
|
||
|
||
/* fourth byte? */
|
||
if ((intval & ~0xff000000) == 0)
|
||
{
|
||
intval = (intval >> 24) & 0xff;
|
||
operands[0] = adj_offsettable_operand (operands[0], 3);
|
||
goto byte_or_operation;
|
||
}
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return AS2 (or%L0,%2,%0);
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_insn "iorhi3"
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
|
||
(ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
|
||
(match_operand:HI 2 "general_operand" "ri,rm")))]
|
||
""
|
||
"*
|
||
{
|
||
HOST_WIDE_INT intval;
|
||
switch (GET_CODE (operands[2]))
|
||
{
|
||
case CONST_INT:
|
||
|
||
if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
|
||
break;
|
||
|
||
/* don't try to optimize volatile accesses */
|
||
if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
|
||
break;
|
||
|
||
intval = 0xffff & INTVAL (operands[2]);
|
||
|
||
if ((intval & 0xff00) == 0)
|
||
{
|
||
if (REG_P (operands[0]))
|
||
{
|
||
/* Do low byte access only for %eax or when high bit is set */
|
||
if (REGNO (operands[0]) != 0 && !(intval & 0x80))
|
||
break;
|
||
}
|
||
|
||
byte_or_operation:
|
||
CC_STATUS_INIT;
|
||
|
||
if (intval == 0xff)
|
||
return AS2 (mov%B0,%2,%b0);
|
||
|
||
return AS2 (or%B0,%2,%b0);
|
||
}
|
||
|
||
/* high byte? */
|
||
if ((intval & 0xff) == 0)
|
||
{
|
||
intval >>= 8;
|
||
operands[2] = GEN_INT (intval);
|
||
|
||
if (REG_P (operands[0]))
|
||
{
|
||
CC_STATUS_INIT;
|
||
if (intval == 0xff)
|
||
return AS2 (mov%B0,%2,%h0);
|
||
|
||
return AS2 (or%B0,%2,%h0);
|
||
}
|
||
|
||
operands[0] = adj_offsettable_operand (operands[0], 1);
|
||
|
||
goto byte_or_operation;
|
||
}
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
if (REG_P (operands[0])
|
||
&& i386_aligned_p (operands[2]))
|
||
{
|
||
CC_STATUS_INIT;
|
||
operands[2] = i386_sext16_if_const (operands[2]);
|
||
return AS2 (or%L0,%k2,%k0);
|
||
}
|
||
|
||
if (GET_CODE (operands[2]) == CONST_INT
|
||
&& i386_aligned_p (operands[0]))
|
||
{
|
||
CC_STATUS_INIT;
|
||
intval = 0xffff & INTVAL (operands[2]);
|
||
if (intval != INTVAL (operands[2]))
|
||
operands[2] = GEN_INT (intval);
|
||
return AS2 (or%L0,%2,%k0);
|
||
}
|
||
|
||
return AS2 (or%W0,%2,%0);
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_insn "iorqi3"
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
|
||
(ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
|
||
(match_operand:QI 2 "general_operand" "qn,qmn")))]
|
||
""
|
||
"* return AS2 (or%B0,%2,%0);"
|
||
[(set_attr "type" "binary")])
|
||
|
||
;;- xor instructions
|
||
|
||
(define_insn "xorsi3"
|
||
[(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")))]
|
||
""
|
||
"*
|
||
{
|
||
HOST_WIDE_INT intval;
|
||
switch (GET_CODE (operands[2]))
|
||
{
|
||
case CONST_INT:
|
||
|
||
if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
|
||
break;
|
||
|
||
/* don't try to optimize volatile accesses */
|
||
if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
|
||
break;
|
||
|
||
intval = INTVAL (operands[2]);
|
||
if ((intval & ~0xff) == 0)
|
||
{
|
||
if (REG_P (operands[0]))
|
||
{
|
||
/* Do low byte access only for %eax or when high bit is set */
|
||
if (REGNO (operands[0]) != 0 && !(intval & 0x80))
|
||
break;
|
||
}
|
||
|
||
byte_xor_operation:
|
||
CC_STATUS_INIT;
|
||
|
||
if (intval == 0xff
|
||
&& (!TARGET_PENTIUM || optimize_size
|
||
|| (GET_CODE (operands[0]) == MEM
|
||
&& memory_address_info (XEXP (operands[0], 0), 1))))
|
||
return AS1 (not%B0,%b0);
|
||
|
||
if (intval != INTVAL (operands[2]))
|
||
operands[2] = GEN_INT (intval);
|
||
return AS2 (xor%B0,%2,%b0);
|
||
}
|
||
|
||
/* second byte? */
|
||
if ((intval & ~0xff00) == 0)
|
||
{
|
||
intval >>= 8;
|
||
|
||
if (REG_P (operands[0]))
|
||
{
|
||
CC_STATUS_INIT;
|
||
if (intval == 0xff
|
||
&& (!TARGET_PENTIUM || optimize_size
|
||
|| (GET_CODE (operands[0]) == MEM
|
||
&& memory_address_info (XEXP (operands[0], 0), 1))))
|
||
return AS1 (not%B0,%h0);
|
||
|
||
operands[2] = GEN_INT (intval);
|
||
return AS2 (xor%B0,%2,%h0);
|
||
}
|
||
|
||
operands[0] = adj_offsettable_operand (operands[0], 1);
|
||
|
||
goto byte_xor_operation;
|
||
}
|
||
|
||
if (REG_P (operands[0]))
|
||
break;
|
||
|
||
/* third byte? */
|
||
if ((intval & ~0xff0000) == 0)
|
||
{
|
||
intval >>= 16;
|
||
operands[0] = adj_offsettable_operand (operands[0], 2);
|
||
goto byte_xor_operation;
|
||
}
|
||
|
||
/* fourth byte? */
|
||
if ((intval & ~0xff000000) == 0)
|
||
{
|
||
intval = (intval >> 24) & 0xff;
|
||
operands[0] = adj_offsettable_operand (operands[0], 3);
|
||
goto byte_xor_operation;
|
||
}
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return AS2 (xor%L0,%2,%0);
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_insn "xorhi3"
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
|
||
(xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
|
||
(match_operand:HI 2 "general_operand" "ri,rm")))]
|
||
""
|
||
"*
|
||
{
|
||
if (GET_CODE (operands[2]) == CONST_INT
|
||
&& ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
|
||
{
|
||
/* Can we ignore the upper byte? */
|
||
if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
|
||
&& (INTVAL (operands[2]) & 0xff00) == 0)
|
||
{
|
||
CC_STATUS_INIT;
|
||
if (INTVAL (operands[2]) & 0xffff0000)
|
||
operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff);
|
||
|
||
if (INTVAL (operands[2]) == 0xff
|
||
&& (!TARGET_PENTIUM || optimize_size
|
||
|| (GET_CODE (operands[0]) == MEM
|
||
&& memory_address_info (XEXP (operands[0], 0), 1))))
|
||
return AS1 (not%B0,%b0);
|
||
|
||
return AS2 (xor%B0,%2,%b0);
|
||
}
|
||
|
||
/* Can we ignore the lower byte? */
|
||
/* ??? what about offsettable memory references? */
|
||
if (QI_REG_P (operands[0])
|
||
&& (INTVAL (operands[2]) & 0xff) == 0)
|
||
{
|
||
CC_STATUS_INIT;
|
||
operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
|
||
|
||
if (INTVAL (operands[2]) == 0xff
|
||
&& (!TARGET_PENTIUM || optimize_size
|
||
|| (GET_CODE (operands[0]) == MEM
|
||
&& memory_address_info (XEXP (operands[0], 0), 1))))
|
||
return AS1 (not%B0,%h0);
|
||
|
||
return AS2 (xor%B0,%2,%h0);
|
||
}
|
||
}
|
||
|
||
if (REG_P (operands[0])
|
||
&& i386_aligned_p (operands[2]))
|
||
{
|
||
CC_STATUS_INIT;
|
||
operands[2] = i386_sext16_if_const (operands[2]);
|
||
return AS2 (xor%L0,%k2,%k0);
|
||
}
|
||
|
||
if (GET_CODE (operands[2]) == CONST_INT
|
||
&& i386_aligned_p (operands[0]))
|
||
{
|
||
HOST_WIDE_INT intval;
|
||
CC_STATUS_INIT;
|
||
intval = 0xffff & INTVAL (operands[2]);
|
||
if (intval != INTVAL (operands[2]))
|
||
operands[2] = GEN_INT (intval);
|
||
return AS2 (xor%L0,%2,%k0);
|
||
}
|
||
|
||
return AS2 (xor%W0,%2,%0);
|
||
}"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_insn "xorqi3"
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
|
||
(xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
|
||
(match_operand:QI 2 "general_operand" "qn,qm")))]
|
||
""
|
||
"* return AS2 (xor%B0,%2,%0);"
|
||
[(set_attr "type" "binary")])
|
||
|
||
;; logical operations for DImode
|
||
|
||
(define_insn "anddi3"
|
||
[(set (match_operand:DI 0 "general_operand" "=&r,&ro")
|
||
(and:DI (match_operand:DI 1 "general_operand" "%0,0")
|
||
(match_operand:DI 2 "general_operand" "oriF,riF")))]
|
||
""
|
||
"#"
|
||
[(set_attr "type" "binary")])
|
||
|
||
|
||
(define_insn "iordi3"
|
||
[(set (match_operand:DI 0 "general_operand" "=&r,&ro")
|
||
(ior:DI (match_operand:DI 1 "general_operand" "%0,0")
|
||
(match_operand:DI 2 "general_operand" "oriF,riF")))]
|
||
""
|
||
"#"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_insn "xordi3"
|
||
[(set (match_operand:DI 0 "general_operand" "=&r,&ro")
|
||
(xor:DI (match_operand:DI 1 "general_operand" "%0,0")
|
||
(match_operand:DI 2 "general_operand" "oriF,riF")))]
|
||
""
|
||
"#"
|
||
[(set_attr "type" "binary")])
|
||
|
||
(define_split
|
||
[(set (match_operand:DI 0 "general_operand" "")
|
||
(match_operator:DI 3 "ix86_logical_operator"
|
||
[(match_operand:DI 1 "general_operand" "")
|
||
(match_operand:DI 2 "general_operand" "")]))]
|
||
""
|
||
[(set (match_dup 4) (match_op_dup:SI 3 [(match_dup 6) (match_dup 8)]))
|
||
(set (match_dup 5) (match_op_dup:SI 3 [(match_dup 7) (match_dup 9)]))]
|
||
"split_di (&operands[0], 1, &operands[4], &operands[5]);
|
||
split_di (&operands[1], 1, &operands[6], &operands[7]);
|
||
split_di (&operands[2], 1, &operands[8], &operands[9]);")
|
||
|
||
;;- negation instructions
|
||
|
||
(define_insn "negdi2"
|
||
[(set (match_operand:DI 0 "general_operand" "=&ro")
|
||
(neg:DI (match_operand:DI 1 "general_operand" "0")))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops[2], low[1], high[1];
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
split_di (operands, 1, low, high);
|
||
xops[0] = const0_rtx;
|
||
xops[1] = high[0];
|
||
|
||
output_asm_insn (AS1 (neg%L0,%0), low);
|
||
output_asm_insn (AS2 (adc%L1,%0,%1), xops);
|
||
output_asm_insn (AS1 (neg%L0,%0), high);
|
||
RET;
|
||
}")
|
||
|
||
(define_insn "negsi2"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
||
(neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
|
||
""
|
||
"neg%L0 %0")
|
||
|
||
(define_insn "neghi2"
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
|
||
(neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
|
||
""
|
||
"*
|
||
if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
|
||
{
|
||
CC_STATUS_INIT;
|
||
return AS1(neg%L0,%k0);
|
||
}
|
||
return AS1(neg%W0,%0);")
|
||
|
||
(define_insn "negqi2"
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
|
||
(neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
|
||
""
|
||
"neg%B0 %0")
|
||
|
||
(define_insn "negsf2"
|
||
[(set (match_operand:SF 0 "register_operand" "=f")
|
||
(neg:SF (match_operand:SF 1 "register_operand" "0")))]
|
||
"TARGET_80387"
|
||
"fchs"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_insn "negdf2"
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(neg:DF (match_operand:DF 1 "register_operand" "0")))]
|
||
"TARGET_80387"
|
||
"fchs"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(neg:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))]
|
||
"TARGET_80387"
|
||
"fchs"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_insn "negxf2"
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(neg:XF (match_operand:XF 1 "register_operand" "0")))]
|
||
"TARGET_80387"
|
||
"fchs"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(neg:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))]
|
||
"TARGET_80387"
|
||
"fchs"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
;; Absolute value instructions
|
||
|
||
(define_insn "abssf2"
|
||
[(set (match_operand:SF 0 "register_operand" "=f")
|
||
(abs:SF (match_operand:SF 1 "register_operand" "0")))]
|
||
"TARGET_80387"
|
||
"fabs"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_insn "absdf2"
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(abs:DF (match_operand:DF 1 "register_operand" "0")))]
|
||
"TARGET_80387"
|
||
"fabs"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(abs:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))]
|
||
"TARGET_80387"
|
||
"fabs"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_insn "absxf2"
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(abs:XF (match_operand:XF 1 "register_operand" "0")))]
|
||
"TARGET_80387"
|
||
"fabs"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(abs:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))]
|
||
"TARGET_80387"
|
||
"fabs"
|
||
[(set_attr "type" "fpop")])
|
||
|
||
(define_insn "sqrtsf2"
|
||
[(set (match_operand:SF 0 "register_operand" "=f")
|
||
(sqrt:SF (match_operand:SF 1 "register_operand" "0")))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
|
||
"fsqrt")
|
||
|
||
(define_insn "sqrtdf2"
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(sqrt:DF (match_operand:DF 1 "register_operand" "0")))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
|
||
&& (TARGET_IEEE_FP || flag_fast_math) "
|
||
"fsqrt")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(sqrt:DF (float_extend:DF
|
||
(match_operand:SF 1 "register_operand" "0"))))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
|
||
"fsqrt")
|
||
|
||
(define_insn "sqrtxf2"
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(sqrt:XF (match_operand:XF 1 "register_operand" "0")))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
|
||
&& (TARGET_IEEE_FP || flag_fast_math) "
|
||
"fsqrt")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(sqrt:XF (float_extend:XF
|
||
(match_operand:DF 1 "register_operand" "0"))))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
|
||
"fsqrt")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(sqrt:XF (float_extend:XF
|
||
(match_operand:SF 1 "register_operand" "0"))))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
|
||
"fsqrt")
|
||
|
||
(define_insn "sindf2"
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
|
||
"fsin")
|
||
|
||
(define_insn "sinsf2"
|
||
[(set (match_operand:SF 0 "register_operand" "=f")
|
||
(unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
|
||
"fsin")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(unspec:DF [(float_extend:DF
|
||
(match_operand:SF 1 "register_operand" "0"))] 1))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
|
||
"fsin")
|
||
|
||
(define_insn "sinxf2"
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(unspec:XF [(match_operand:XF 1 "register_operand" "0")] 1))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
|
||
"fsin")
|
||
|
||
(define_insn "cosdf2"
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
|
||
"fcos")
|
||
|
||
(define_insn "cossf2"
|
||
[(set (match_operand:SF 0 "register_operand" "=f")
|
||
(unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
|
||
"fcos")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f")
|
||
(unspec:DF [(float_extend:DF
|
||
(match_operand:SF 1 "register_operand" "0"))] 2))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
|
||
"fcos")
|
||
|
||
(define_insn "cosxf2"
|
||
[(set (match_operand:XF 0 "register_operand" "=f")
|
||
(unspec:XF [(match_operand:XF 1 "register_operand" "0")] 2))]
|
||
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
|
||
"fcos")
|
||
|
||
;;- one complement instructions
|
||
|
||
(define_insn "one_cmplsi2"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
||
(not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
|
||
""
|
||
"*
|
||
{
|
||
/* A Pentium NOT is not pariable. Output it only in case of complex
|
||
memory address, because XOR will be inpariable anyway because
|
||
of immediate/displacement rule. */
|
||
|
||
if (TARGET_PENTIUM && !optimize_size
|
||
&& (GET_CODE (operands[0]) != MEM
|
||
|| memory_address_info (XEXP (operands[0], 0), 1) == 0))
|
||
{
|
||
rtx xops[2];
|
||
xops[0] = operands[0];
|
||
xops[1] = GEN_INT (0xffffffff);
|
||
output_asm_insn (AS2 (xor%L0,%1,%0), xops);
|
||
RET;
|
||
}
|
||
else
|
||
return AS1 (not%L0,%0);
|
||
}")
|
||
|
||
(define_insn "one_cmplhi2"
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
|
||
(not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
|
||
""
|
||
"*
|
||
{
|
||
/* A Pentium NOT is not pariable. Output it only in case of complex
|
||
memory address, because XOR will be inpariable anyway because
|
||
of immediate/displacement rule. */
|
||
|
||
if (TARGET_PENTIUM && !optimize_size
|
||
&& (GET_CODE (operands[0]) != MEM
|
||
|| memory_address_info (XEXP (operands[0], 0), 1) == 0))
|
||
{
|
||
rtx xops[2];
|
||
xops[0] = operands[0];
|
||
xops[1] = GEN_INT (0xffff);
|
||
if (REG_P (operands[0])
|
||
&& i386_cc_probably_useless_p (insn))
|
||
{
|
||
CC_STATUS_INIT;
|
||
output_asm_insn (AS2 (xor%L0,%1,%k0), xops);
|
||
}
|
||
else
|
||
output_asm_insn (AS2 (xor%W0,%1,%0), xops);
|
||
RET;
|
||
}
|
||
else
|
||
{
|
||
if (REG_P (operands[0])
|
||
&& i386_cc_probably_useless_p (insn))
|
||
{
|
||
CC_STATUS_INIT;
|
||
return AS1 (not%L0,%k0);
|
||
}
|
||
return AS1 (not%W0,%0);
|
||
}
|
||
}")
|
||
|
||
(define_insn "one_cmplqi2"
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
|
||
(not:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
|
||
""
|
||
"*
|
||
{
|
||
/* A Pentium NOT is not pariable. Output it only in case of complex
|
||
memory address, because XOR will be inpariable anyway because
|
||
of immediate/displacement rule. */
|
||
|
||
if (TARGET_PENTIUM && !optimize_size
|
||
&& (GET_CODE (operands[0]) != MEM
|
||
|| memory_address_info (XEXP (operands[0], 0), 1) == 0))
|
||
{
|
||
rtx xops[2];
|
||
xops[0] = operands[0];
|
||
xops[1] = GEN_INT (0xff);
|
||
output_asm_insn (AS2 (xor%B0,%1,%0), xops);
|
||
RET;
|
||
}
|
||
else
|
||
return AS1 (not%B0,%0);
|
||
}")
|
||
|
||
;;- 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 "ashldi3"
|
||
[(set (match_operand:DI 0 "register_operand" "")
|
||
(ashift:DI (match_operand:DI 1 "register_operand" "")
|
||
(match_operand:QI 2 "nonmemory_operand" "")))]
|
||
""
|
||
"
|
||
{
|
||
if (GET_CODE (operands[2]) != CONST_INT
|
||
|| ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J'))
|
||
{
|
||
operands[2] = copy_to_mode_reg (QImode, operands[2]);
|
||
emit_insn (gen_ashldi3_non_const_int (operands[0], operands[1],
|
||
operands[2]));
|
||
}
|
||
else
|
||
emit_insn (gen_ashldi3_const_int (operands[0], operands[1], operands[2]));
|
||
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "ashldi3_const_int"
|
||
[(set (match_operand:DI 0 "register_operand" "=&r")
|
||
(ashift:DI (match_operand:DI 1 "register_operand" "0")
|
||
(match_operand:QI 2 "const_int_operand" "J")))]
|
||
"CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')"
|
||
"*
|
||
{
|
||
rtx xops[4], low[1], high[1];
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
split_di (operands, 1, low, high);
|
||
xops[0] = operands[2];
|
||
xops[1] = const1_rtx;
|
||
xops[2] = low[0];
|
||
xops[3] = high[0];
|
||
|
||
if (INTVAL (xops[0]) > 31)
|
||
{
|
||
output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */
|
||
output_asm_insn (AS2 (xor%L2,%2,%2), xops);
|
||
|
||
if (INTVAL (xops[0]) > 32)
|
||
{
|
||
xops[0] = GEN_INT (INTVAL (xops[0]) - 32);
|
||
output_asm_insn (AS2 (sal%L3,%0,%3), xops); /* Remaining shift */
|
||
}
|
||
}
|
||
else
|
||
{
|
||
output_asm_insn (AS3 (shld%L3,%0,%2,%3), xops);
|
||
output_asm_insn (AS2 (sal%L2,%0,%2), xops);
|
||
}
|
||
RET;
|
||
}")
|
||
|
||
(define_insn "ashldi3_non_const_int"
|
||
[(set (match_operand:DI 0 "register_operand" "=&r")
|
||
(ashift:DI (match_operand:DI 1 "register_operand" "0")
|
||
(match_operand:QI 2 "register_operand" "c")))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops[5], low[1], high[1];
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
split_di (operands, 1, low, high);
|
||
xops[0] = operands[2];
|
||
xops[1] = GEN_INT (32);
|
||
xops[2] = low[0];
|
||
xops[3] = high[0];
|
||
xops[4] = gen_label_rtx ();
|
||
|
||
output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops);
|
||
output_asm_insn (AS2 (sal%L2,%0,%2), xops);
|
||
output_asm_insn (AS2 (test%B0,%1,%b0), xops);
|
||
output_asm_insn (AS1 (je,%X4), xops);
|
||
output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */
|
||
output_asm_insn (AS2 (xor%L2,%2,%2), xops);
|
||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
|
||
CODE_LABEL_NUMBER (xops[4]));
|
||
RET;
|
||
}")
|
||
|
||
(define_expand "ashlsi3"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "")
|
||
(ashift:SI (match_operand:SI 1 "nonimmediate_operand" "")
|
||
(match_operand:SI 2 "nonmemory_operand" "")))]
|
||
""
|
||
"")
|
||
|
||
(define_expand "ashlhi3"
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "")
|
||
(ashift:HI (match_operand:HI 1 "nonimmediate_operand" "")
|
||
(match_operand:HI 2 "nonmemory_operand" "")))]
|
||
""
|
||
"")
|
||
|
||
(define_expand "ashlqi3"
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "")
|
||
(ashift:QI (match_operand:QI 1 "nonimmediate_operand" "")
|
||
(match_operand:QI 2 "nonmemory_operand" "")))]
|
||
""
|
||
"")
|
||
|
||
;; Pattern for shifts which can be encoded into an lea instruction.
|
||
;; This is kept as a separate pattern so that regmove can optimize cases
|
||
;; where we know the source and destination must match.
|
||
;;
|
||
;; Do not expose this pattern when optimizing for size since we never want
|
||
;; to use lea when optimizing for size since mov+sal is smaller than lea.
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r")
|
||
(ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,r")
|
||
(match_operand:SI 2 "small_shift_operand" "M,M")))]
|
||
"! optimize_size"
|
||
"* return output_ashl (insn, operands);")
|
||
|
||
;; Generic left shift pattern to catch all cases not handled by the
|
||
;; shift pattern above.
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
||
(ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0")
|
||
(match_operand:SI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"* return output_ashl (insn, operands);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r")
|
||
(ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0,r")
|
||
(match_operand:HI 2 "small_shift_operand" "M,M")))]
|
||
"! optimize_size"
|
||
"* return output_ashl (insn, operands);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
|
||
(ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0")
|
||
(match_operand:HI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"* return output_ashl (insn, operands);")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=q,q")
|
||
(ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,q")
|
||
(match_operand:QI 2 "small_shift_operand" "M,M")))]
|
||
"! optimize_size"
|
||
"* return output_ashl (insn, operands);")
|
||
|
||
;; Generic left shift pattern to catch all cases not handled by the
|
||
;; shift pattern above.
|
||
(define_insn ""
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
|
||
(ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0")
|
||
(match_operand:QI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"* return output_ashl (insn, operands);")
|
||
|
||
;; See comment above `ashldi3' about how this works.
|
||
|
||
(define_expand "ashrdi3"
|
||
[(set (match_operand:DI 0 "register_operand" "")
|
||
(ashiftrt:DI (match_operand:DI 1 "register_operand" "")
|
||
(match_operand:QI 2 "nonmemory_operand" "")))]
|
||
""
|
||
"
|
||
{
|
||
if (GET_CODE (operands[2]) != CONST_INT
|
||
|| ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J'))
|
||
{
|
||
operands[2] = copy_to_mode_reg (QImode, operands[2]);
|
||
emit_insn (gen_ashrdi3_non_const_int (operands[0], operands[1],
|
||
operands[2]));
|
||
}
|
||
else
|
||
emit_insn (gen_ashrdi3_const_int (operands[0], operands[1], operands[2]));
|
||
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "ashldi3_32"
|
||
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,m")
|
||
(ashift:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
|
||
(const_int 32)))]
|
||
""
|
||
"*
|
||
{
|
||
rtx low[2], high[2], xops[4];
|
||
|
||
split_di (operands, 2, low, high);
|
||
xops[0] = high[0];
|
||
xops[1] = low[1];
|
||
xops[2] = low[0];
|
||
xops[3] = const0_rtx;
|
||
if (!rtx_equal_p (xops[0], xops[1]))
|
||
output_asm_insn (AS2 (mov%L0,%1,%0), xops);
|
||
|
||
if (GET_CODE (low[0]) == MEM)
|
||
output_asm_insn (AS2 (mov%L2,%3,%2), xops);
|
||
else
|
||
output_asm_insn (AS2 (xor%L2,%2,%2), xops);
|
||
|
||
RET;
|
||
}")
|
||
|
||
(define_insn "ashrdi3_const_int"
|
||
[(set (match_operand:DI 0 "register_operand" "=&r")
|
||
(ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
|
||
(match_operand:QI 2 "const_int_operand" "J")))]
|
||
"CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')"
|
||
"*
|
||
{
|
||
rtx xops[4], low[1], high[1];
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
split_di (operands, 1, low, high);
|
||
xops[0] = operands[2];
|
||
xops[1] = const1_rtx;
|
||
xops[2] = low[0];
|
||
xops[3] = high[0];
|
||
|
||
if (INTVAL (xops[0]) > 31)
|
||
{
|
||
xops[1] = GEN_INT (31);
|
||
output_asm_insn (AS2 (mov%L2,%3,%2), xops);
|
||
output_asm_insn (AS2 (sar%L3,%1,%3), xops); /* shift by 32 */
|
||
|
||
if (INTVAL (xops[0]) > 32)
|
||
{
|
||
xops[0] = GEN_INT (INTVAL (xops[0]) - 32);
|
||
output_asm_insn (AS2 (sar%L2,%0,%2), xops); /* Remaining shift */
|
||
}
|
||
}
|
||
else
|
||
{
|
||
output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops);
|
||
output_asm_insn (AS2 (sar%L3,%0,%3), xops);
|
||
}
|
||
|
||
RET;
|
||
}")
|
||
|
||
(define_insn "ashrdi3_non_const_int"
|
||
[(set (match_operand:DI 0 "register_operand" "=&r")
|
||
(ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
|
||
(match_operand:QI 2 "register_operand" "c")))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops[5], low[1], high[1];
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
split_di (operands, 1, low, high);
|
||
xops[0] = operands[2];
|
||
xops[1] = GEN_INT (32);
|
||
xops[2] = low[0];
|
||
xops[3] = high[0];
|
||
xops[4] = gen_label_rtx ();
|
||
|
||
output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
|
||
output_asm_insn (AS2 (sar%L3,%0,%3), xops);
|
||
output_asm_insn (AS2 (test%B0,%1,%b0), xops);
|
||
output_asm_insn (AS1 (je,%X4), xops);
|
||
xops[1] = GEN_INT (31);
|
||
output_asm_insn (AS2 (mov%L2,%3,%2), xops);
|
||
output_asm_insn (AS2 (sar%L3,%1,%3), xops); /* shift by 32 */
|
||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
|
||
CODE_LABEL_NUMBER (xops[4]));
|
||
RET;
|
||
}")
|
||
|
||
(define_insn "ashrsi3_31"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm,d")
|
||
(ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,a")
|
||
(const_int 31)))]
|
||
"!TARGET_PENTIUM || optimize_size"
|
||
"@
|
||
sar%L0 $31,%0
|
||
cltd")
|
||
|
||
(define_insn "ashrsi3"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
||
(ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
|
||
(match_operand:SI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (sar%L0,%b2,%0);
|
||
else
|
||
return AS2 (sar%L0,%2,%0);
|
||
}")
|
||
|
||
(define_insn "ashrhi3"
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
|
||
(ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
|
||
(match_operand:HI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (sar%W0,%b2,%0);
|
||
else
|
||
return AS2 (sar%W0,%2,%0);
|
||
}")
|
||
|
||
(define_insn "ashrqi3"
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
|
||
(ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
|
||
(match_operand:QI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (sar%B0,%b2,%0);
|
||
else
|
||
return AS2 (sar%B0,%2,%0);
|
||
}")
|
||
|
||
;;- logical shift instructions
|
||
|
||
;; See comment above `ashldi3' about how this works.
|
||
|
||
(define_expand "lshrdi3"
|
||
[(set (match_operand:DI 0 "register_operand" "")
|
||
(lshiftrt:DI (match_operand:DI 1 "register_operand" "")
|
||
(match_operand:QI 2 "nonmemory_operand" "")))]
|
||
""
|
||
"
|
||
{
|
||
if (GET_CODE (operands[2]) != CONST_INT
|
||
|| ! CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J'))
|
||
{
|
||
operands[2] = copy_to_mode_reg (QImode, operands[2]);
|
||
emit_insn (gen_lshrdi3_non_const_int (operands[0], operands[1],
|
||
operands[2]));
|
||
}
|
||
else
|
||
emit_insn (gen_lshrdi3_const_int (operands[0], operands[1], operands[2]));
|
||
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "lshrdi3_32"
|
||
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,m")
|
||
(lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
|
||
(const_int 32)))]
|
||
""
|
||
"*
|
||
{
|
||
rtx low[2], high[2], xops[4];
|
||
|
||
split_di (operands, 2, low, high);
|
||
xops[0] = low[0];
|
||
xops[1] = high[1];
|
||
xops[2] = high[0];
|
||
xops[3] = const0_rtx;
|
||
if (!rtx_equal_p (xops[0], xops[1]))
|
||
output_asm_insn (AS2 (mov%L0,%1,%0), xops);
|
||
|
||
if (GET_CODE (low[0]) == MEM)
|
||
output_asm_insn (AS2 (mov%L2,%3,%2), xops);
|
||
else
|
||
output_asm_insn (AS2 (xor%L2,%2,%2), xops);
|
||
|
||
RET;
|
||
}")
|
||
|
||
(define_insn "lshrdi3_const_int"
|
||
[(set (match_operand:DI 0 "register_operand" "=&r")
|
||
(lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
|
||
(match_operand:QI 2 "const_int_operand" "J")))]
|
||
"CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')"
|
||
"*
|
||
{
|
||
rtx xops[4], low[1], high[1];
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
split_di (operands, 1, low, high);
|
||
xops[0] = operands[2];
|
||
xops[1] = const1_rtx;
|
||
xops[2] = low[0];
|
||
xops[3] = high[0];
|
||
|
||
if (INTVAL (xops[0]) > 31)
|
||
{
|
||
output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */
|
||
output_asm_insn (AS2 (xor%L3,%3,%3), xops);
|
||
|
||
if (INTVAL (xops[0]) > 32)
|
||
{
|
||
xops[0] = GEN_INT (INTVAL (xops[0]) - 32);
|
||
output_asm_insn (AS2 (shr%L2,%0,%2), xops); /* Remaining shift */
|
||
}
|
||
}
|
||
else
|
||
{
|
||
output_asm_insn (AS3 (shrd%L2,%0,%3,%2), xops);
|
||
output_asm_insn (AS2 (shr%L3,%0,%3), xops);
|
||
}
|
||
|
||
RET;
|
||
}")
|
||
|
||
(define_insn "lshrdi3_non_const_int"
|
||
[(set (match_operand:DI 0 "register_operand" "=&r")
|
||
(lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
|
||
(match_operand:QI 2 "register_operand" "c")))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops[5], low[1], high[1];
|
||
|
||
CC_STATUS_INIT;
|
||
|
||
split_di (operands, 1, low, high);
|
||
xops[0] = operands[2];
|
||
xops[1] = GEN_INT (32);
|
||
xops[2] = low[0];
|
||
xops[3] = high[0];
|
||
xops[4] = gen_label_rtx ();
|
||
|
||
output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
|
||
output_asm_insn (AS2 (shr%L3,%0,%3), xops);
|
||
output_asm_insn (AS2 (test%B0,%1,%b0), xops);
|
||
output_asm_insn (AS1 (je,%X4), xops);
|
||
output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */
|
||
output_asm_insn (AS2 (xor%L3,%3,%3), xops);
|
||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
|
||
CODE_LABEL_NUMBER (xops[4]));
|
||
RET;
|
||
}")
|
||
|
||
(define_insn "lshrsi3"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
||
(lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
|
||
(match_operand:SI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (shr%L0,%b2,%0);
|
||
else
|
||
return AS2 (shr%L0,%2,%1);
|
||
}")
|
||
|
||
(define_insn "lshrhi3"
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
|
||
(lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
|
||
(match_operand:HI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (shr%W0,%b2,%0);
|
||
else
|
||
return AS2 (shr%W0,%2,%0);
|
||
}")
|
||
|
||
(define_insn "lshrqi3"
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
|
||
(lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
|
||
(match_operand:QI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (shr%B0,%b2,%0);
|
||
else
|
||
return AS2 (shr%B0,%2,%0);
|
||
}")
|
||
|
||
;;- rotate instructions
|
||
|
||
(define_insn "rotlsi3"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
||
(rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0")
|
||
(match_operand:SI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (rol%L0,%b2,%0);
|
||
else
|
||
return AS2 (rol%L0,%2,%0);
|
||
}")
|
||
|
||
(define_insn "rotlhi3"
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
|
||
(rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0")
|
||
(match_operand:HI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (rol%W0,%b2,%0);
|
||
else
|
||
return AS2 (rol%W0,%2,%0);
|
||
}")
|
||
|
||
(define_insn "rotlqi3"
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
|
||
(rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0")
|
||
(match_operand:QI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (rol%B0,%b2,%0);
|
||
else
|
||
return AS2 (rol%B0,%2,%0);
|
||
}")
|
||
|
||
(define_insn "rotrsi3"
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
||
(rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0")
|
||
(match_operand:SI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (ror%L0,%b2,%0);
|
||
else
|
||
return AS2 (ror%L0,%2,%0);
|
||
}")
|
||
|
||
(define_insn "rotrhi3"
|
||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
|
||
(rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0")
|
||
(match_operand:HI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (ror%W0,%b2,%0);
|
||
else
|
||
return AS2 (ror%W0,%2,%0);
|
||
}")
|
||
|
||
(define_insn "rotrqi3"
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
|
||
(rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0")
|
||
(match_operand:QI 2 "nonmemory_operand" "cI")))]
|
||
""
|
||
"*
|
||
{
|
||
if (REG_P (operands[2]))
|
||
return AS2 (ror%B0,%b2,%0);
|
||
else
|
||
return AS2 (ror%B0,%2,%0);
|
||
}")
|
||
|
||
/*
|
||
;; This usually looses. But try a define_expand to recognize a few case
|
||
;; we can do efficiently, such as accessing the "high" QImode registers,
|
||
;; %ah, %bh, %ch, %dh.
|
||
;; ??? Note this has a botch on the mode of operand 0, which needs to be
|
||
;; fixed if this is ever enabled.
|
||
(define_insn "insv"
|
||
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+&r")
|
||
(match_operand:SI 1 "immediate_operand" "i")
|
||
(match_operand:SI 2 "immediate_operand" "i"))
|
||
(match_operand:SI 3 "nonmemory_operand" "ri"))]
|
||
""
|
||
"*
|
||
{
|
||
if (INTVAL (operands[1]) + INTVAL (operands[2]) > GET_MODE_BITSIZE (SImode))
|
||
abort ();
|
||
if (GET_CODE (operands[3]) == CONST_INT)
|
||
{
|
||
unsigned int mask = (1 << INTVAL (operands[1])) - 1;
|
||
operands[1] = GEN_INT (~(mask << INTVAL (operands[2])));
|
||
output_asm_insn (AS2 (and%L0,%1,%0), operands);
|
||
operands[3] = GEN_INT (INTVAL (operands[3]) << INTVAL (operands[2]));
|
||
output_asm_insn (AS2 (or%L0,%3,%0), operands);
|
||
}
|
||
else
|
||
{
|
||
operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
|
||
if (INTVAL (operands[2]))
|
||
output_asm_insn (AS2 (ror%L0,%2,%0), operands);
|
||
output_asm_insn (AS3 (shrd%L0,%1,%3,%0), operands);
|
||
operands[2] = GEN_INT (BITS_PER_WORD
|
||
- INTVAL (operands[1]) - INTVAL (operands[2]));
|
||
if (INTVAL (operands[2]))
|
||
output_asm_insn (AS2 (ror%L0,%2,%0), operands);
|
||
}
|
||
RET;
|
||
}")
|
||
*/
|
||
/*
|
||
;; ??? There are problems with the mode of operand[3]. The point of this
|
||
;; is to represent an HImode move to a "high byte" register.
|
||
|
||
(define_expand "insv"
|
||
[(set (zero_extract:SI (match_operand:SI 0 "general_operand" "")
|
||
(match_operand:SI 1 "immediate_operand" "")
|
||
(match_operand:SI 2 "immediate_operand" ""))
|
||
(match_operand:QI 3 "nonmemory_operand" "ri"))]
|
||
""
|
||
"
|
||
{
|
||
if (GET_CODE (operands[1]) != CONST_INT
|
||
|| GET_CODE (operands[2]) != CONST_INT)
|
||
FAIL;
|
||
|
||
if (! (INTVAL (operands[1]) == 8
|
||
&& (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 0))
|
||
&& ! INTVAL (operands[1]) == 1)
|
||
FAIL;
|
||
}")
|
||
*/
|
||
|
||
;; On i386, the register count for a bit operation is *not* truncated,
|
||
;; so SHIFT_COUNT_TRUNCATED must not be defined.
|
||
|
||
;; On i486, the shift & or/and code is faster than bts or btr. If
|
||
;; operands[0] is a MEM, the bt[sr] is half as fast as the normal code.
|
||
|
||
;; On i386, bts is a little faster if operands[0] is a reg, and a
|
||
;; little slower if operands[0] is a MEM, than the shift & or/and code.
|
||
;; Use bts & btr, since they reload better.
|
||
|
||
;; General bit set and clear.
|
||
(define_insn ""
|
||
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+rm")
|
||
(const_int 1)
|
||
(match_operand:SI 2 "register_operand" "r"))
|
||
(match_operand:SI 3 "const_int_operand" "n"))]
|
||
"TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT"
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
|
||
if (INTVAL (operands[3]) == 1)
|
||
return AS2 (bts%L0,%2,%0);
|
||
else
|
||
return AS2 (btr%L0,%2,%0);
|
||
}")
|
||
|
||
;; Bit complement. See comments on previous pattern.
|
||
;; ??? Is this really worthwhile?
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
||
(xor:SI (ashift:SI (const_int 1)
|
||
(match_operand:SI 1 "register_operand" "r"))
|
||
(match_operand:SI 2 "nonimmediate_operand" "0")))]
|
||
"TARGET_USE_BIT_TEST && GET_CODE (operands[1]) != CONST_INT"
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
|
||
return AS2 (btc%L0,%1,%0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
|
||
(xor:SI (match_operand:SI 1 "nonimmediate_operand" "0")
|
||
(ashift:SI (const_int 1)
|
||
(match_operand:SI 2 "register_operand" "r"))))]
|
||
"TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT"
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
|
||
return AS2 (btc%L0,%2,%0);
|
||
}")
|
||
|
||
;; Recognizers for bit-test instructions.
|
||
|
||
;; The bt opcode allows a MEM in operands[0]. But on both i386 and
|
||
;; i486, it is faster to copy a MEM to REG and then use bt, than to use
|
||
;; bt on the MEM directly.
|
||
|
||
;; ??? The first argument of a zero_extract must not be reloaded, so
|
||
;; don't allow a MEM in the operand predicate without allowing it in the
|
||
;; constraint.
|
||
|
||
(define_insn ""
|
||
[(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r")
|
||
(const_int 1)
|
||
(match_operand:SI 1 "register_operand" "r")))]
|
||
"GET_CODE (operands[1]) != CONST_INT"
|
||
"*
|
||
{
|
||
cc_status.flags |= CC_Z_IN_NOT_C;
|
||
return AS2 (bt%L0,%1,%0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r")
|
||
(match_operand:SI 1 "const_int_operand" "n")
|
||
(match_operand:SI 2 "const_int_operand" "n")))]
|
||
""
|
||
"*
|
||
{
|
||
unsigned int mask;
|
||
|
||
mask = ((1 << INTVAL (operands[1])) - 1) << INTVAL (operands[2]);
|
||
operands[1] = GEN_INT (mask);
|
||
|
||
if (QI_REG_P (operands[0])
|
||
/* A Pentium test is pairable only with eax. Not with ah or al. */
|
||
&& (! REG_P (operands[0]) || REGNO (operands[0]) || !TARGET_PENTIUM
|
||
|| optimize_size))
|
||
{
|
||
if ((mask & ~0xff) == 0)
|
||
{
|
||
cc_status.flags |= CC_NOT_NEGATIVE;
|
||
return AS2 (test%B0,%1,%b0);
|
||
}
|
||
|
||
if ((mask & ~0xff00) == 0)
|
||
{
|
||
cc_status.flags |= CC_NOT_NEGATIVE;
|
||
operands[1] = GEN_INT (mask >> 8);
|
||
return AS2 (test%B0,%1,%h0);
|
||
}
|
||
}
|
||
|
||
return AS2 (test%L0,%1,%0);
|
||
}")
|
||
|
||
;; ??? All bets are off if operand 0 is a volatile MEM reference.
|
||
;; The CPU may access unspecified bytes around the actual target byte.
|
||
|
||
(define_insn ""
|
||
[(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "m")
|
||
(match_operand:SI 1 "const_int_operand" "n")
|
||
(match_operand:SI 2 "const_int_operand" "n")))]
|
||
"GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0])"
|
||
"*
|
||
{
|
||
unsigned int mask;
|
||
|
||
mask = ((1 << INTVAL (operands[1])) - 1) << INTVAL (operands[2]);
|
||
operands[1] = GEN_INT (mask);
|
||
|
||
if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
|
||
/* A Pentium test is pairable only with eax. Not with ah or al. */
|
||
&& (! REG_P (operands[0]) || REGNO (operands[0]) || !TARGET_PENTIUM
|
||
|| optimize_size))
|
||
{
|
||
if ((mask & ~0xff) == 0)
|
||
{
|
||
cc_status.flags |= CC_NOT_NEGATIVE;
|
||
return AS2 (test%B0,%1,%b0);
|
||
}
|
||
|
||
if ((mask & ~0xff00) == 0)
|
||
{
|
||
cc_status.flags |= CC_NOT_NEGATIVE;
|
||
operands[1] = GEN_INT (mask >> 8);
|
||
|
||
if (QI_REG_P (operands[0]))
|
||
return AS2 (test%B0,%1,%h0);
|
||
else
|
||
{
|
||
operands[0] = adj_offsettable_operand (operands[0], 1);
|
||
return AS2 (test%B0,%1,%b0);
|
||
}
|
||
}
|
||
|
||
if (GET_CODE (operands[0]) == MEM && (mask & ~0xff0000) == 0)
|
||
{
|
||
cc_status.flags |= CC_NOT_NEGATIVE;
|
||
operands[1] = GEN_INT (mask >> 16);
|
||
operands[0] = adj_offsettable_operand (operands[0], 2);
|
||
return AS2 (test%B0,%1,%b0);
|
||
}
|
||
|
||
if (GET_CODE (operands[0]) == MEM && (mask & ~0xff000000) == 0)
|
||
{
|
||
cc_status.flags |= CC_NOT_NEGATIVE;
|
||
operands[1] = GEN_INT (mask >> 24);
|
||
operands[0] = adj_offsettable_operand (operands[0], 3);
|
||
return AS2 (test%B0,%1,%b0);
|
||
}
|
||
}
|
||
|
||
if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
|
||
return AS2 (test%L0,%1,%0);
|
||
|
||
return AS2 (test%L1,%0,%1);
|
||
}")
|
||
|
||
;; Store-flag instructions.
|
||
|
||
;; For all sCOND expanders, also expand the compare or test insn that
|
||
;; generates cc0. Generate an equality comparison if `seq' or `sne'.
|
||
|
||
(define_expand "seq"
|
||
[(match_dup 1)
|
||
(set (match_operand:QI 0 "register_operand" "")
|
||
(eq:QI (cc0) (const_int 0)))]
|
||
""
|
||
"
|
||
{
|
||
if (TARGET_IEEE_FP
|
||
&& GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
|
||
operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
|
||
else
|
||
operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
|
||
}")
|
||
|
||
(define_expand "sne"
|
||
[(match_dup 1)
|
||
(set (match_operand:QI 0 "register_operand" "")
|
||
(ne:QI (cc0) (const_int 0)))]
|
||
""
|
||
"
|
||
{
|
||
if (TARGET_IEEE_FP
|
||
&& GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
|
||
operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
|
||
else
|
||
operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
|
||
}")
|
||
|
||
(define_expand "sgt"
|
||
[(match_dup 1)
|
||
(set (match_operand:QI 0 "register_operand" "")
|
||
(gt:QI (cc0) (const_int 0)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "sgtu"
|
||
[(match_dup 1)
|
||
(set (match_operand:QI 0 "register_operand" "")
|
||
(gtu:QI (cc0) (const_int 0)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "slt"
|
||
[(match_dup 1)
|
||
(set (match_operand:QI 0 "register_operand" "")
|
||
(lt:QI (cc0) (const_int 0)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "sltu"
|
||
[(match_dup 1)
|
||
(set (match_operand:QI 0 "register_operand" "")
|
||
(ltu:QI (cc0) (const_int 0)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "sge"
|
||
[(match_dup 1)
|
||
(set (match_operand:QI 0 "register_operand" "")
|
||
(ge:QI (cc0) (const_int 0)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "sgeu"
|
||
[(match_dup 1)
|
||
(set (match_operand:QI 0 "register_operand" "")
|
||
(geu:QI (cc0) (const_int 0)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "sle"
|
||
[(match_dup 1)
|
||
(set (match_operand:QI 0 "register_operand" "")
|
||
(le:QI (cc0) (const_int 0)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "sleu"
|
||
[(match_dup 1)
|
||
(set (match_operand:QI 0 "register_operand" "")
|
||
(leu:QI (cc0) (const_int 0)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
;; The 386 sCOND opcodes can write to memory. But a gcc sCOND insn may
|
||
;; not have any input reloads. A MEM write might need an input reload
|
||
;; for the address of the MEM. So don't allow MEM as the SET_DEST.
|
||
|
||
(define_insn "*setcc"
|
||
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
|
||
(match_operator:QI 1 "comparison_operator" [(cc0) (const_int 0)]))]
|
||
"reload_completed || register_operand (operands[0], QImode)"
|
||
"*
|
||
{
|
||
enum rtx_code code = GET_CODE (operands[1]);
|
||
if (cc_prev_status.flags & CC_TEST_AX)
|
||
{
|
||
int eq;
|
||
HOST_WIDE_INT c;
|
||
operands[2] = gen_rtx_REG (SImode, 0);
|
||
switch (code)
|
||
{
|
||
case EQ:
|
||
c = 0x4000;
|
||
eq = 0;
|
||
break;
|
||
case NE:
|
||
c = 0x4000;
|
||
eq = 1;
|
||
break;
|
||
case GT:
|
||
c = 0x4100;
|
||
eq = 1;
|
||
break;
|
||
case LT:
|
||
c = 0x100;
|
||
eq = 0;
|
||
break;
|
||
case GE:
|
||
c = 0x100;
|
||
eq = 1;
|
||
break;
|
||
case LE:
|
||
c = 0x4100;
|
||
eq = 0;
|
||
break;
|
||
default:
|
||
abort ();
|
||
}
|
||
if (!TARGET_PENTIUM || optimize_size)
|
||
{
|
||
operands[3] = GEN_INT (c >> 8);
|
||
output_asm_insn (AS2 (test%B0,%3,%h2), operands);
|
||
}
|
||
else
|
||
{
|
||
operands[3] = GEN_INT (c);
|
||
output_asm_insn (AS2 (test%L0,%3,%2), operands);
|
||
}
|
||
return eq ? AS1 (sete,%0) : AS1 (setne, %0);
|
||
}
|
||
|
||
if ((cc_status.flags & CC_NO_OVERFLOW) && (code == LE || code == GT))
|
||
return (char *)0;
|
||
return AS1(set%D1,%0);
|
||
}")
|
||
|
||
|
||
;; Basic conditional jump instructions.
|
||
;; We ignore the overflow flag for signed branch instructions.
|
||
|
||
;; For all bCOND expanders, also expand the compare or test insn that
|
||
;; generates cc0. Generate an equality comparison if `beq' or `bne'.
|
||
|
||
(define_expand "beq"
|
||
[(match_dup 1)
|
||
(set (pc)
|
||
(if_then_else (eq (cc0)
|
||
(const_int 0))
|
||
(label_ref (match_operand 0 "" ""))
|
||
(pc)))]
|
||
""
|
||
"
|
||
{
|
||
if (TARGET_IEEE_FP
|
||
&& GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
|
||
operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
|
||
else
|
||
operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
|
||
}")
|
||
|
||
(define_expand "bne"
|
||
[(match_dup 1)
|
||
(set (pc)
|
||
(if_then_else (ne (cc0)
|
||
(const_int 0))
|
||
(label_ref (match_operand 0 "" ""))
|
||
(pc)))]
|
||
""
|
||
"
|
||
{
|
||
if (TARGET_IEEE_FP
|
||
&& GET_MODE_CLASS (GET_MODE (i386_compare_op0)) == MODE_FLOAT)
|
||
operands[1] = (*i386_compare_gen_eq)(i386_compare_op0, i386_compare_op1);
|
||
else
|
||
operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);
|
||
}")
|
||
|
||
|
||
(define_expand "bgt"
|
||
[(match_dup 1)
|
||
(set (pc)
|
||
(if_then_else (gt (cc0)
|
||
(const_int 0))
|
||
(label_ref (match_operand 0 "" ""))
|
||
(pc)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "bgtu"
|
||
[(match_dup 1)
|
||
(set (pc)
|
||
(if_then_else (gtu (cc0)
|
||
(const_int 0))
|
||
(label_ref (match_operand 0 "" ""))
|
||
(pc)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "blt"
|
||
[(match_dup 1)
|
||
(set (pc)
|
||
(if_then_else (lt (cc0)
|
||
(const_int 0))
|
||
(label_ref (match_operand 0 "" ""))
|
||
(pc)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
|
||
(define_expand "bltu"
|
||
[(match_dup 1)
|
||
(set (pc)
|
||
(if_then_else (ltu (cc0)
|
||
(const_int 0))
|
||
(label_ref (match_operand 0 "" ""))
|
||
(pc)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "bge"
|
||
[(match_dup 1)
|
||
(set (pc)
|
||
(if_then_else (ge (cc0)
|
||
(const_int 0))
|
||
(label_ref (match_operand 0 "" ""))
|
||
(pc)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "bgeu"
|
||
[(match_dup 1)
|
||
(set (pc)
|
||
(if_then_else (geu (cc0)
|
||
(const_int 0))
|
||
(label_ref (match_operand 0 "" ""))
|
||
(pc)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "ble"
|
||
[(match_dup 1)
|
||
(set (pc)
|
||
(if_then_else (le (cc0)
|
||
(const_int 0))
|
||
(label_ref (match_operand 0 "" ""))
|
||
(pc)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_expand "bleu"
|
||
[(match_dup 1)
|
||
(set (pc)
|
||
(if_then_else (leu (cc0)
|
||
(const_int 0))
|
||
(label_ref (match_operand 0 "" ""))
|
||
(pc)))]
|
||
""
|
||
"operands[1] = (*i386_compare_gen)(i386_compare_op0, i386_compare_op1);")
|
||
|
||
(define_insn ""
|
||
[(set (pc)
|
||
(if_then_else (match_operator 0 "comparison_operator"
|
||
[(cc0) (const_int 0)])
|
||
(label_ref (match_operand 1 "" ""))
|
||
(pc)))]
|
||
""
|
||
"*
|
||
{
|
||
enum rtx_code code = GET_CODE (operands[0]);
|
||
if (cc_prev_status.flags & CC_TEST_AX)
|
||
{
|
||
int eq;
|
||
HOST_WIDE_INT c;
|
||
operands[2] = gen_rtx_REG (SImode, 0);
|
||
switch (code)
|
||
{
|
||
case EQ:
|
||
c = 0x4000;
|
||
eq = 0;
|
||
break;
|
||
case NE:
|
||
c = 0x4000;
|
||
eq = 1;
|
||
break;
|
||
case GT:
|
||
c = 0x4100;
|
||
eq = 1;
|
||
break;
|
||
case LT:
|
||
c = 0x100;
|
||
eq = 0;
|
||
break;
|
||
case GE:
|
||
c = 0x100;
|
||
eq = 1;
|
||
break;
|
||
case LE:
|
||
c = 0x4100;
|
||
eq = 0;
|
||
break;
|
||
default:
|
||
abort ();
|
||
}
|
||
if (!TARGET_PENTIUM || optimize_size)
|
||
{
|
||
operands[3] = GEN_INT (c >> 8);
|
||
output_asm_insn (AS2 (test%B0,%3,%h2), operands);
|
||
}
|
||
else
|
||
{
|
||
operands[3] = GEN_INT (c);
|
||
output_asm_insn (AS2 (test%L0,%3,%2), operands);
|
||
}
|
||
return eq ? AS1 (je,%l1) : AS1 (jne, %l1);
|
||
}
|
||
if ((cc_status.flags & CC_NO_OVERFLOW) && (code == LE || code == GT))
|
||
return (char *)0;
|
||
|
||
return AS1(j%D0,%l1);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (pc)
|
||
(if_then_else (match_operator 0 "comparison_operator"
|
||
[(cc0) (const_int 0)])
|
||
(pc)
|
||
(label_ref (match_operand 1 "" ""))))]
|
||
""
|
||
"*
|
||
{
|
||
enum rtx_code code = GET_CODE (operands[0]);
|
||
if (cc_prev_status.flags & CC_TEST_AX)
|
||
{
|
||
int eq;
|
||
HOST_WIDE_INT c;
|
||
operands[2] = gen_rtx_REG (SImode, 0);
|
||
switch (code)
|
||
{
|
||
case EQ:
|
||
c = 0x4000;
|
||
eq = 1;
|
||
break;
|
||
case NE:
|
||
c = 0x4000;
|
||
eq = 0;
|
||
break;
|
||
case GT:
|
||
c = 0x4100;
|
||
eq = 0;
|
||
break;
|
||
case LT:
|
||
c = 0x100;
|
||
eq = 1;
|
||
break;
|
||
case GE:
|
||
c = 0x100;
|
||
eq = 0;
|
||
break;
|
||
case LE:
|
||
c = 0x4100;
|
||
eq = 1;
|
||
break;
|
||
default:
|
||
abort ();
|
||
}
|
||
if (!TARGET_PENTIUM || optimize_size)
|
||
{
|
||
operands[3] = GEN_INT (c >> 8);
|
||
output_asm_insn (AS2 (test%B0,%3,%h2), operands);
|
||
}
|
||
else
|
||
{
|
||
operands[3] = GEN_INT (c);
|
||
output_asm_insn (AS2 (test%L0,%3,%2), operands);
|
||
}
|
||
return eq ? AS1 (je,%l1) : AS1 (jne, %l1);
|
||
}
|
||
if ((cc_status.flags & CC_NO_OVERFLOW) && (code == LE || code == GT))
|
||
return (char *)0;
|
||
|
||
return AS1(j%d0,%l1);
|
||
}")
|
||
|
||
;; Unconditional and other jump instructions
|
||
|
||
(define_insn "jump"
|
||
[(set (pc)
|
||
(label_ref (match_operand 0 "" "")))]
|
||
""
|
||
"jmp %l0"
|
||
[(set_attr "memory" "none")])
|
||
|
||
(define_insn "indirect_jump"
|
||
[(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
|
||
""
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
|
||
return AS1 (jmp,%*%0);
|
||
}"
|
||
[(set_attr "memory" "none")])
|
||
|
||
;; ??? could transform while(--i > 0) S; to if (--i > 0) do S; while(--i);
|
||
;; if S does not change i
|
||
|
||
(define_expand "decrement_and_branch_until_zero"
|
||
[(parallel [(set (pc)
|
||
(if_then_else (ge (plus:SI (match_operand:SI 0 "general_operand" "")
|
||
(const_int -1))
|
||
(const_int 0))
|
||
(label_ref (match_operand 1 "" ""))
|
||
(pc)))
|
||
(set (match_dup 0)
|
||
(plus:SI (match_dup 0)
|
||
(const_int -1)))])]
|
||
""
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (pc)
|
||
(if_then_else (match_operator 0 "arithmetic_comparison_operator"
|
||
[(plus:SI (match_operand:SI 1 "nonimmediate_operand" "+c*r,m")
|
||
(match_operand:SI 2 "general_operand" "rmi,ri"))
|
||
(const_int 0)])
|
||
(label_ref (match_operand 3 "" ""))
|
||
(pc)))
|
||
(set (match_dup 1)
|
||
(plus:SI (match_dup 1)
|
||
(match_dup 2)))]
|
||
""
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
|
||
if (GET_CODE (operands[1]) == REG && REGNO (operands[2]) == 2 &&
|
||
operands[2] == constm1_rtx && ix86_cpu == PROCESSOR_K6)
|
||
return \"loop %l3\";
|
||
|
||
if (operands[2] == constm1_rtx)
|
||
output_asm_insn (AS1 (dec%L1,%1), operands);
|
||
|
||
else if (operands[2] == const1_rtx)
|
||
output_asm_insn (AS1 (inc%L1,%1), operands);
|
||
|
||
else
|
||
output_asm_insn (AS2 (add%L1,%2,%1), operands);
|
||
|
||
return AS1 (%J0,%l3);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (pc)
|
||
(if_then_else (match_operator 0 "arithmetic_comparison_operator"
|
||
[(minus:SI (match_operand:SI 1 "nonimmediate_operand" "+r,m")
|
||
(match_operand:SI 2 "general_operand" "rmi,ri"))
|
||
(const_int 0)])
|
||
(label_ref (match_operand 3 "" ""))
|
||
(pc)))
|
||
(set (match_dup 1)
|
||
(minus:SI (match_dup 1)
|
||
(match_dup 2)))]
|
||
""
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
if (operands[2] == const1_rtx)
|
||
output_asm_insn (AS1 (dec%L1,%1), operands);
|
||
|
||
else if (operands[1] == constm1_rtx)
|
||
output_asm_insn (AS1 (inc%L1,%1), operands);
|
||
|
||
else
|
||
output_asm_insn (AS2 (sub%L1,%2,%1), operands);
|
||
|
||
return AS1 (%J0,%l3);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (pc)
|
||
(if_then_else (ne (match_operand:SI 0 "general_operand" "+g")
|
||
(const_int 0))
|
||
(label_ref (match_operand 1 "" ""))
|
||
(pc)))
|
||
(set (match_dup 0)
|
||
(plus:SI (match_dup 0)
|
||
(const_int -1)))]
|
||
""
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
operands[2] = const1_rtx;
|
||
output_asm_insn (AS2 (sub%L0,%2,%0), operands);
|
||
return \"jnc %l1\";
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (pc)
|
||
(if_then_else (eq (match_operand:SI 0 "general_operand" "+g")
|
||
(const_int 0))
|
||
(label_ref (match_operand 1 "" ""))
|
||
(pc)))
|
||
(set (match_dup 0)
|
||
(plus:SI (match_dup 0)
|
||
(const_int -1)))]
|
||
""
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
operands[2] = const1_rtx;
|
||
output_asm_insn (AS2 (sub%L0,%2,%0), operands);
|
||
return \"jc %l1\";
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (pc)
|
||
(if_then_else (ne (match_operand:SI 0 "general_operand" "+g")
|
||
(const_int 1))
|
||
(label_ref (match_operand 1 "" ""))
|
||
(pc)))
|
||
(set (match_dup 0)
|
||
(plus:SI (match_dup 0)
|
||
(const_int -1)))]
|
||
""
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
output_asm_insn (AS1 (dec%L0,%0), operands);
|
||
return \"jnz %l1\";
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (pc)
|
||
(if_then_else (eq (match_operand:SI 0 "general_operand" "+g")
|
||
(const_int 1))
|
||
(label_ref (match_operand 1 "" ""))
|
||
(pc)))
|
||
(set (match_dup 0)
|
||
(plus:SI (match_dup 0)
|
||
(const_int -1)))]
|
||
""
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
output_asm_insn (AS1 (dec%L0,%0), operands);
|
||
return \"jz %l1\";
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (pc)
|
||
(if_then_else (ne (match_operand:SI 0 "general_operand" "+g")
|
||
(const_int -1))
|
||
(label_ref (match_operand 1 "" ""))
|
||
(pc)))
|
||
(set (match_dup 0)
|
||
(plus:SI (match_dup 0)
|
||
(const_int 1)))]
|
||
""
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
output_asm_insn (AS1 (inc%L0,%0), operands);
|
||
return \"jnz %l1\";
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (pc)
|
||
(if_then_else (eq (match_operand:SI 0 "general_operand" "+g")
|
||
(const_int -1))
|
||
(label_ref (match_operand 1 "" ""))
|
||
(pc)))
|
||
(set (match_dup 0)
|
||
(plus:SI (match_dup 0)
|
||
(const_int 1)))]
|
||
""
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
output_asm_insn (AS1 (inc%L0,%0), operands);
|
||
return \"jz %l1\";
|
||
}")
|
||
|
||
;; Implement switch statements when generating PIC code. Switches are
|
||
;; implemented by `tablejump' when not using -fpic.
|
||
|
||
;; Emit code here to do the range checking and make the index zero based.
|
||
|
||
(define_expand "casesi"
|
||
[(set (match_dup 5)
|
||
(match_operand:SI 0 "general_operand" ""))
|
||
(set (match_dup 6)
|
||
(minus:SI (match_dup 5)
|
||
(match_operand:SI 1 "general_operand" "")))
|
||
(set (cc0)
|
||
(compare:CC (match_dup 6)
|
||
(match_operand:SI 2 "general_operand" "")))
|
||
(set (pc)
|
||
(if_then_else (gtu (cc0)
|
||
(const_int 0))
|
||
(label_ref (match_operand 4 "" ""))
|
||
(pc)))
|
||
(parallel
|
||
[(set (pc)
|
||
(minus:SI (reg:SI 3)
|
||
(mem:SI (plus:SI (mult:SI (match_dup 6)
|
||
(const_int 4))
|
||
(label_ref (match_operand 3 "" ""))))))
|
||
(clobber (match_scratch:SI 7 ""))])]
|
||
"flag_pic"
|
||
"
|
||
{
|
||
operands[5] = gen_reg_rtx (SImode);
|
||
operands[6] = gen_reg_rtx (SImode);
|
||
current_function_uses_pic_offset_table = 1;
|
||
}")
|
||
|
||
;; Implement a casesi insn.
|
||
|
||
;; Each entry in the "addr_diff_vec" looks like this as the result of the
|
||
;; two rules below:
|
||
;;
|
||
;; .long _GLOBAL_OFFSET_TABLE_+[.-.L2]
|
||
;;
|
||
;; 1. An expression involving an external reference may only use the
|
||
;; addition operator, and only with an assembly-time constant.
|
||
;; The example above satisfies this because ".-.L2" is a constant.
|
||
;;
|
||
;; 2. The symbol _GLOBAL_OFFSET_TABLE_ is magic, and at link time is
|
||
;; given the value of "GOT - .", where GOT is the actual address of
|
||
;; the Global Offset Table. Therefore, the .long above actually
|
||
;; stores the value "( GOT - . ) + [ . - .L2 ]", or "GOT - .L2". The
|
||
;; expression "GOT - .L2" by itself would generate an error from as(1).
|
||
;;
|
||
;; The pattern below emits code that looks like this:
|
||
;;
|
||
;; movl %ebx,reg
|
||
;; subl TABLE@GOTOFF(%ebx,index,4),reg
|
||
;; jmp reg
|
||
;;
|
||
;; The addr_diff_vec contents may be directly referenced with @GOTOFF, since
|
||
;; the addr_diff_vec is known to be part of this module.
|
||
;;
|
||
;; The subl above calculates "GOT - (( GOT - . ) + [ . - .L2 ])", which
|
||
;; evaluates to just ".L2".
|
||
|
||
(define_insn ""
|
||
[(set (pc)
|
||
(minus:SI (reg:SI 3)
|
||
(mem:SI (plus:SI
|
||
(mult:SI (match_operand:SI 0 "register_operand" "r")
|
||
(const_int 4))
|
||
(label_ref (match_operand 1 "" ""))))))
|
||
(clobber (match_scratch:SI 2 "=&r"))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops[4];
|
||
|
||
xops[0] = operands[0];
|
||
xops[1] = operands[1];
|
||
xops[2] = operands[2];
|
||
xops[3] = pic_offset_table_rtx;
|
||
|
||
output_asm_insn (AS2 (mov%L2,%3,%2), xops);
|
||
output_asm_insn (\"sub%L2 %l1@GOTOFF(%3,%0,4),%2\", xops);
|
||
output_asm_insn (AS1 (jmp,%*%2), xops);
|
||
ASM_OUTPUT_ALIGN (asm_out_file, i386_align_jumps);
|
||
RET;
|
||
}")
|
||
|
||
(define_insn "tablejump"
|
||
[(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))
|
||
(use (label_ref (match_operand 1 "" "")))]
|
||
""
|
||
"*
|
||
{
|
||
CC_STATUS_INIT;
|
||
|
||
return AS1 (jmp,%*%0);
|
||
}")
|
||
|
||
;; Call insns.
|
||
|
||
;; If generating PIC code, the predicate indirect_operand will fail
|
||
;; for operands[0] containing symbolic references on all of the named
|
||
;; call* patterns. Each named pattern is followed by an unnamed pattern
|
||
;; that matches any call to a symbolic CONST (ie, a symbol_ref). The
|
||
;; unnamed patterns are only used while generating PIC code, because
|
||
;; otherwise the named patterns match.
|
||
|
||
;; Call subroutine returning no value.
|
||
|
||
(define_expand "call_pop"
|
||
[(parallel [(call (match_operand:QI 0 "indirect_operand" "")
|
||
(match_operand:SI 1 "general_operand" ""))
|
||
(set (reg:SI 7)
|
||
(plus:SI (reg:SI 7)
|
||
(match_operand:SI 3 "immediate_operand" "")))])]
|
||
""
|
||
"
|
||
{
|
||
rtx addr;
|
||
|
||
if (operands[3] == const0_rtx)
|
||
{
|
||
emit_insn (gen_call (operands[0], operands[1]));
|
||
DONE;
|
||
}
|
||
|
||
if (flag_pic)
|
||
current_function_uses_pic_offset_table = 1;
|
||
|
||
/* With half-pic, force the address into a register. */
|
||
addr = XEXP (operands[0], 0);
|
||
if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
|
||
XEXP (operands[0], 0) = force_reg (Pmode, addr);
|
||
|
||
if (! expander_call_insn_operand (operands[0], QImode))
|
||
operands[0]
|
||
= change_address (operands[0], VOIDmode,
|
||
copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(call (match_operand:QI 0 "call_insn_operand" "m")
|
||
(match_operand:SI 1 "general_operand" "g"))
|
||
(set (reg:SI 7) (plus:SI (reg:SI 7)
|
||
(match_operand:SI 3 "immediate_operand" "i")))]
|
||
""
|
||
"*
|
||
{
|
||
if (GET_CODE (operands[0]) == MEM
|
||
&& ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
||
{
|
||
operands[0] = XEXP (operands[0], 0);
|
||
return AS1 (call,%*%0);
|
||
}
|
||
else
|
||
return AS1 (call,%P0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
|
||
(match_operand:SI 1 "general_operand" "g"))
|
||
(set (reg:SI 7) (plus:SI (reg:SI 7)
|
||
(match_operand:SI 3 "immediate_operand" "i")))]
|
||
"!HALF_PIC_P ()"
|
||
"call %P0")
|
||
|
||
(define_expand "call"
|
||
[(call (match_operand:QI 0 "indirect_operand" "")
|
||
(match_operand:SI 1 "general_operand" ""))]
|
||
;; Operand 1 not used on the i386.
|
||
""
|
||
"
|
||
{
|
||
rtx addr;
|
||
|
||
if (flag_pic)
|
||
current_function_uses_pic_offset_table = 1;
|
||
|
||
/* With half-pic, force the address into a register. */
|
||
addr = XEXP (operands[0], 0);
|
||
if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
|
||
XEXP (operands[0], 0) = force_reg (Pmode, addr);
|
||
|
||
if (! expander_call_insn_operand (operands[0], QImode))
|
||
operands[0]
|
||
= change_address (operands[0], VOIDmode,
|
||
copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(call (match_operand:QI 0 "call_insn_operand" "m")
|
||
(match_operand:SI 1 "general_operand" "g"))]
|
||
;; Operand 1 not used on the i386.
|
||
""
|
||
"*
|
||
{
|
||
if (GET_CODE (operands[0]) == MEM
|
||
&& ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
|
||
{
|
||
operands[0] = XEXP (operands[0], 0);
|
||
return AS1 (call,%*%0);
|
||
}
|
||
else
|
||
return AS1 (call,%P0);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
|
||
(match_operand:SI 1 "general_operand" "g"))]
|
||
;; Operand 1 not used on the i386.
|
||
"!HALF_PIC_P ()"
|
||
"call %P0")
|
||
|
||
;; Call subroutine, returning value in operand 0
|
||
;; (which must be a hard register).
|
||
|
||
(define_expand "call_value_pop"
|
||
[(parallel [(set (match_operand 0 "" "")
|
||
(call (match_operand:QI 1 "indirect_operand" "")
|
||
(match_operand:SI 2 "general_operand" "")))
|
||
(set (reg:SI 7)
|
||
(plus:SI (reg:SI 7)
|
||
(match_operand:SI 4 "immediate_operand" "")))])]
|
||
""
|
||
"
|
||
{
|
||
rtx addr;
|
||
|
||
if (operands[4] == const0_rtx)
|
||
{
|
||
emit_insn (gen_call_value (operands[0], operands[1], operands[2]));
|
||
DONE;
|
||
}
|
||
|
||
if (flag_pic)
|
||
current_function_uses_pic_offset_table = 1;
|
||
|
||
/* With half-pic, force the address into a register. */
|
||
addr = XEXP (operands[1], 0);
|
||
if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
|
||
XEXP (operands[1], 0) = force_reg (Pmode, addr);
|
||
|
||
if (! expander_call_insn_operand (operands[1], QImode))
|
||
operands[1]
|
||
= change_address (operands[1], VOIDmode,
|
||
copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand 0 "" "=rf")
|
||
(call (match_operand:QI 1 "call_insn_operand" "m")
|
||
(match_operand:SI 2 "general_operand" "g")))
|
||
(set (reg:SI 7) (plus:SI (reg:SI 7)
|
||
(match_operand:SI 4 "immediate_operand" "i")))]
|
||
""
|
||
"*
|
||
{
|
||
if (GET_CODE (operands[1]) == MEM
|
||
&& ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
||
{
|
||
operands[1] = XEXP (operands[1], 0);
|
||
output_asm_insn (AS1 (call,%*%1), operands);
|
||
}
|
||
else
|
||
output_asm_insn (AS1 (call,%P1), operands);
|
||
|
||
RET;
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand 0 "" "=rf")
|
||
(call (mem:QI (match_operand:SI 1 "symbolic_operand" ""))
|
||
(match_operand:SI 2 "general_operand" "g")))
|
||
(set (reg:SI 7) (plus:SI (reg:SI 7)
|
||
(match_operand:SI 4 "immediate_operand" "i")))]
|
||
"!HALF_PIC_P ()"
|
||
"call %P1")
|
||
|
||
(define_expand "call_value"
|
||
[(set (match_operand 0 "" "")
|
||
(call (match_operand:QI 1 "indirect_operand" "")
|
||
(match_operand:SI 2 "general_operand" "")))]
|
||
;; Operand 2 not used on the i386.
|
||
""
|
||
"
|
||
{
|
||
rtx addr;
|
||
|
||
if (flag_pic)
|
||
current_function_uses_pic_offset_table = 1;
|
||
|
||
/* With half-pic, force the address into a register. */
|
||
addr = XEXP (operands[1], 0);
|
||
if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
|
||
XEXP (operands[1], 0) = force_reg (Pmode, addr);
|
||
|
||
if (! expander_call_insn_operand (operands[1], QImode))
|
||
operands[1]
|
||
= change_address (operands[1], VOIDmode,
|
||
copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand 0 "" "=rf")
|
||
(call (match_operand:QI 1 "call_insn_operand" "m")
|
||
(match_operand:SI 2 "general_operand" "g")))]
|
||
;; Operand 2 not used on the i386.
|
||
""
|
||
"*
|
||
{
|
||
if (GET_CODE (operands[1]) == MEM
|
||
&& ! CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
|
||
{
|
||
operands[1] = XEXP (operands[1], 0);
|
||
output_asm_insn (AS1 (call,%*%1), operands);
|
||
}
|
||
else
|
||
output_asm_insn (AS1 (call,%P1), operands);
|
||
|
||
RET;
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand 0 "" "=rf")
|
||
(call (mem:QI (match_operand:SI 1 "symbolic_operand" ""))
|
||
(match_operand:SI 2 "general_operand" "g")))]
|
||
;; Operand 2 not used on the i386.
|
||
"!HALF_PIC_P ()"
|
||
"call %P1")
|
||
|
||
;; Call subroutine returning any type.
|
||
|
||
(define_expand "untyped_call"
|
||
[(parallel [(call (match_operand 0 "" "")
|
||
(const_int 0))
|
||
(match_operand 1 "" "")
|
||
(match_operand 2 "" "")])]
|
||
""
|
||
"
|
||
{
|
||
int i;
|
||
|
||
/* In order to give reg-stack an easier job in validating two
|
||
coprocessor registers as containing a possible return value,
|
||
simply pretend the untyped call returns a complex long double
|
||
value. */
|
||
|
||
emit_call_insn (TARGET_80387
|
||
? gen_call_value (gen_rtx_REG (XCmode, FIRST_FLOAT_REG),
|
||
operands[0], const0_rtx)
|
||
: gen_call (operands[0], const0_rtx));
|
||
|
||
for (i = 0; i < XVECLEN (operands[2], 0); i++)
|
||
{
|
||
rtx set = XVECEXP (operands[2], 0, i);
|
||
emit_move_insn (SET_DEST (set), SET_SRC (set));
|
||
}
|
||
|
||
/* The optimizer does not know that the call sets the function value
|
||
registers we stored in the result block. We avoid problems by
|
||
claiming that all hard registers are used and clobbered at this
|
||
point. */
|
||
emit_insn (gen_blockage ());
|
||
|
||
DONE;
|
||
}")
|
||
|
||
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
|
||
;; all of memory. This blocks insns from being moved across this point.
|
||
|
||
(define_insn "blockage"
|
||
[(unspec_volatile [(const_int 0)] 0)]
|
||
""
|
||
""
|
||
[(set_attr "memory" "none")])
|
||
|
||
;; Insn emitted into the body of a function to return from a function.
|
||
;; This is only done if the function's epilogue is known to be simple.
|
||
;; See comments for simple_386_epilogue in i386.c.
|
||
|
||
(define_expand "return"
|
||
[(return)]
|
||
"ix86_can_use_return_insn_p ()"
|
||
"")
|
||
|
||
(define_insn "return_internal"
|
||
[(return)]
|
||
"reload_completed"
|
||
"ret"
|
||
[(set_attr "memory" "none")])
|
||
|
||
(define_insn "return_pop_internal"
|
||
[(return)
|
||
(use (match_operand:SI 0 "const_int_operand" ""))]
|
||
"reload_completed"
|
||
"ret %0"
|
||
[(set_attr "memory" "none")])
|
||
|
||
(define_insn "nop"
|
||
[(const_int 0)]
|
||
""
|
||
"nop"
|
||
[(set_attr "memory" "none")])
|
||
|
||
(define_expand "prologue"
|
||
[(const_int 1)]
|
||
""
|
||
"
|
||
{
|
||
ix86_expand_prologue ();
|
||
DONE;
|
||
}")
|
||
|
||
;; The use of UNSPEC here is currently not necessary - a simple SET of ebp
|
||
;; to itself would be enough. But this way we are safe even if some optimizer
|
||
;; becomes too clever in the future.
|
||
(define_insn "prologue_set_stack_ptr"
|
||
[(set (reg:SI 7)
|
||
(minus:SI (reg:SI 7) (match_operand:SI 0 "immediate_operand" "i")))
|
||
(set (reg:SI 6) (unspec:SI [(reg:SI 6)] 4))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops [2];
|
||
|
||
xops[0] = operands[0];
|
||
xops[1] = stack_pointer_rtx;
|
||
output_asm_insn (AS2 (sub%L1,%0,%1), xops);
|
||
RET;
|
||
}"
|
||
[(set_attr "memory" "none")])
|
||
|
||
(define_insn "prologue_set_got"
|
||
[(set (match_operand:SI 0 "" "")
|
||
(unspec_volatile
|
||
[(plus:SI (match_dup 0)
|
||
(plus:SI (match_operand:SI 1 "symbolic_operand" "")
|
||
(minus:SI (pc) (match_operand 2 "" ""))))] 1))]
|
||
""
|
||
"*
|
||
{
|
||
char buffer[64];
|
||
|
||
if (TARGET_DEEP_BRANCH_PREDICTION)
|
||
{
|
||
sprintf (buffer, \"addl %s,%%0\", XSTR (operands[1], 0));
|
||
output_asm_insn (buffer, operands);
|
||
}
|
||
else
|
||
{
|
||
sprintf (buffer, \"addl %s+[.-%%X2],%%0\", XSTR (operands[1], 0));
|
||
output_asm_insn (buffer, operands);
|
||
}
|
||
RET;
|
||
}")
|
||
|
||
(define_insn "prologue_get_pc"
|
||
[(set (match_operand:SI 0 "" "")
|
||
(unspec_volatile [(plus:SI (pc) (match_operand 1 "" ""))] 2))]
|
||
""
|
||
"*
|
||
{
|
||
output_asm_insn (AS1 (call,%X1), operands);
|
||
if (! TARGET_DEEP_BRANCH_PREDICTION)
|
||
{
|
||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (operands[1]));
|
||
}
|
||
RET;
|
||
}"
|
||
[(set_attr "memory" "none")])
|
||
|
||
(define_insn "prologue_get_pc_and_set_got"
|
||
[(unspec_volatile [(match_operand:SI 0 "" "")] 3)]
|
||
""
|
||
"*
|
||
{
|
||
operands[1] = gen_label_rtx ();
|
||
output_asm_insn (AS1 (call,%X1), operands);
|
||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
|
||
CODE_LABEL_NUMBER (operands[1]));
|
||
output_asm_insn (AS1 (pop%L0,%0), operands);
|
||
output_asm_insn (\"addl $%__GLOBAL_OFFSET_TABLE_+[.-%X1],%0\", operands);
|
||
RET;
|
||
}"
|
||
[(set_attr "memory" "none")])
|
||
|
||
(define_expand "epilogue"
|
||
[(const_int 1)]
|
||
""
|
||
"
|
||
{
|
||
ix86_expand_epilogue ();
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "epilogue_set_stack_ptr"
|
||
[(set (reg:SI 7) (reg:SI 6))
|
||
(clobber (reg:SI 6))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops [2];
|
||
|
||
xops[0] = frame_pointer_rtx;
|
||
xops[1] = stack_pointer_rtx;
|
||
output_asm_insn (AS2 (mov%L0,%0,%1), xops);
|
||
RET;
|
||
}"
|
||
[(set_attr "memory" "none")])
|
||
|
||
(define_insn "leave"
|
||
[(const_int 2)
|
||
(clobber (reg:SI 6))
|
||
(clobber (reg:SI 7))]
|
||
""
|
||
"leave"
|
||
[(set_attr "memory" "none")])
|
||
|
||
(define_insn "pop"
|
||
[(set (match_operand:SI 0 "register_operand" "r")
|
||
(mem:SI (reg:SI 7)))
|
||
(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))]
|
||
""
|
||
"*
|
||
{
|
||
output_asm_insn (AS1 (pop%L0,%P0), operands);
|
||
RET;
|
||
}"
|
||
[(set_attr "memory" "load")])
|
||
|
||
(define_expand "movstrsi"
|
||
[(parallel [(set (match_operand:BLK 0 "memory_operand" "")
|
||
(match_operand:BLK 1 "memory_operand" ""))
|
||
(use (match_operand:SI 2 "const_int_operand" ""))
|
||
(use (match_operand:SI 3 "const_int_operand" ""))
|
||
(clobber (match_scratch:SI 4 ""))
|
||
(clobber (match_dup 5))
|
||
(clobber (match_dup 6))])]
|
||
""
|
||
"
|
||
{
|
||
rtx addr0, addr1;
|
||
|
||
if (GET_CODE (operands[2]) != CONST_INT)
|
||
FAIL;
|
||
|
||
addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
|
||
addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
|
||
|
||
operands[5] = addr0;
|
||
operands[6] = addr1;
|
||
|
||
operands[0] = change_address (operands[0], VOIDmode, addr0);
|
||
operands[1] = change_address (operands[1], VOIDmode, addr1);
|
||
}")
|
||
|
||
;; It might seem that operands 0 & 1 could use predicate register_operand.
|
||
;; But strength reduction might offset the MEM expression. So we let
|
||
;; reload put the address into %edi & %esi.
|
||
|
||
(define_insn ""
|
||
[(set (mem:BLK (match_operand:SI 0 "address_operand" "D"))
|
||
(mem:BLK (match_operand:SI 1 "address_operand" "S")))
|
||
(use (match_operand:SI 2 "const_int_operand" "n"))
|
||
(use (match_operand:SI 3 "immediate_operand" "i"))
|
||
(clobber (match_scratch:SI 4 "=&c"))
|
||
(clobber (match_dup 0))
|
||
(clobber (match_dup 1))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops[2];
|
||
|
||
output_asm_insn (\"cld\", operands);
|
||
if (GET_CODE (operands[2]) == CONST_INT)
|
||
{
|
||
if (INTVAL (operands[2]) & ~0x03)
|
||
{
|
||
xops[0] = GEN_INT ((INTVAL (operands[2]) >> 2) & 0x3fffffff);
|
||
xops[1] = operands[4];
|
||
|
||
output_asm_insn (AS2 (mov%L1,%0,%1), xops);
|
||
#ifdef INTEL_SYNTAX
|
||
output_asm_insn (\"rep movsd\", xops);
|
||
#else
|
||
output_asm_insn (\"rep\;movsl\", xops);
|
||
#endif
|
||
}
|
||
if (INTVAL (operands[2]) & 0x02)
|
||
output_asm_insn (\"movsw\", operands);
|
||
if (INTVAL (operands[2]) & 0x01)
|
||
output_asm_insn (\"movsb\", operands);
|
||
}
|
||
else
|
||
abort ();
|
||
RET;
|
||
}")
|
||
|
||
(define_expand "clrstrsi"
|
||
[(set (match_dup 3) (const_int 0))
|
||
(parallel [(set (match_operand:BLK 0 "memory_operand" "")
|
||
(const_int 0))
|
||
(use (match_operand:SI 1 "const_int_operand" ""))
|
||
(use (match_operand:SI 2 "const_int_operand" ""))
|
||
(use (match_dup 3))
|
||
(clobber (match_scratch:SI 4 ""))
|
||
(clobber (match_dup 5))])]
|
||
""
|
||
"
|
||
{
|
||
rtx addr0;
|
||
|
||
if (GET_CODE (operands[1]) != CONST_INT)
|
||
FAIL;
|
||
|
||
addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
|
||
|
||
operands[3] = gen_reg_rtx (SImode);
|
||
operands[5] = addr0;
|
||
|
||
operands[0] = gen_rtx_MEM (BLKmode, addr0);
|
||
}")
|
||
|
||
;; It might seem that operand 0 could use predicate register_operand.
|
||
;; But strength reduction might offset the MEM expression. So we let
|
||
;; reload put the address into %edi.
|
||
|
||
(define_insn "*bzero"
|
||
[(set (mem:BLK (match_operand:SI 0 "address_operand" "D"))
|
||
(const_int 0))
|
||
(use (match_operand:SI 1 "const_int_operand" "n"))
|
||
(use (match_operand:SI 2 "immediate_operand" "i"))
|
||
(use (match_operand:SI 3 "register_operand" "a"))
|
||
(clobber (match_scratch:SI 4 "=&c"))
|
||
(clobber (match_dup 0))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops[2];
|
||
|
||
output_asm_insn (\"cld\", operands);
|
||
if (GET_CODE (operands[1]) == CONST_INT)
|
||
{
|
||
unsigned int count = INTVAL (operands[1]) & 0xffffffff;
|
||
if (count & ~0x03)
|
||
{
|
||
xops[0] = GEN_INT (count / 4);
|
||
xops[1] = operands[4];
|
||
|
||
/* K6: stos takes 1 cycle, rep stos takes 8 + %ecx cycles.
|
||
80386: 4/5+5n (+2 for set of ecx)
|
||
80486: 5/7+5n (+1 for set of ecx)
|
||
*/
|
||
if (count / 4 < ((int) ix86_cpu < (int)PROCESSOR_PENTIUM ? 4 : 6))
|
||
{
|
||
do
|
||
#ifdef INTEL_SYNTAX
|
||
output_asm_insn (\"stosd\", xops);
|
||
#else
|
||
output_asm_insn (\"stosl\", xops);
|
||
#endif
|
||
while ((count -= 4) > 3);
|
||
}
|
||
else
|
||
{
|
||
output_asm_insn (AS2 (mov%L1,%0,%1), xops);
|
||
#ifdef INTEL_SYNTAX
|
||
output_asm_insn (\"rep stosd\", xops);
|
||
#else
|
||
output_asm_insn (\"rep\;stosl\", xops);
|
||
#endif
|
||
}
|
||
}
|
||
if (INTVAL (operands[1]) & 0x02)
|
||
output_asm_insn (\"stosw\", operands);
|
||
if (INTVAL (operands[1]) & 0x01)
|
||
output_asm_insn (\"stosb\", operands);
|
||
}
|
||
else
|
||
abort ();
|
||
RET;
|
||
}")
|
||
|
||
(define_expand "cmpstrsi"
|
||
[(parallel [(set (match_operand:SI 0 "general_operand" "")
|
||
(compare:SI (match_operand:BLK 1 "general_operand" "")
|
||
(match_operand:BLK 2 "general_operand" "")))
|
||
(use (match_operand:SI 3 "general_operand" ""))
|
||
(use (match_operand:SI 4 "immediate_operand" ""))
|
||
(clobber (match_dup 5))
|
||
(clobber (match_dup 6))
|
||
(clobber (match_dup 3))])]
|
||
""
|
||
"
|
||
{
|
||
rtx addr1, addr2;
|
||
|
||
addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
|
||
addr2 = copy_to_mode_reg (Pmode, XEXP (operands[2], 0));
|
||
operands[3] = copy_to_mode_reg (SImode, operands[3]);
|
||
|
||
operands[5] = addr1;
|
||
operands[6] = addr2;
|
||
|
||
operands[1] = gen_rtx_MEM (BLKmode, addr1);
|
||
operands[2] = gen_rtx_MEM (BLKmode, addr2);
|
||
|
||
}")
|
||
|
||
;; memcmp recognizers. The `cmpsb' opcode does nothing if the count is
|
||
;; zero. Emit extra code to make sure that a zero-length compare is EQ.
|
||
|
||
;; It might seem that operands 0 & 1 could use predicate register_operand.
|
||
;; But strength reduction might offset the MEM expression. So we let
|
||
;; reload put the address into %edi & %esi.
|
||
|
||
;; ??? Most comparisons have a constant length, and it's therefore
|
||
;; possible to know that the length is non-zero, and to avoid the extra
|
||
;; code to handle zero-length compares.
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "register_operand" "=&r")
|
||
(compare:SI (mem:BLK (match_operand:SI 1 "address_operand" "S"))
|
||
(mem:BLK (match_operand:SI 2 "address_operand" "D"))))
|
||
(use (match_operand:SI 3 "register_operand" "c"))
|
||
(use (match_operand:SI 4 "immediate_operand" "i"))
|
||
(clobber (match_dup 1))
|
||
(clobber (match_dup 2))
|
||
(clobber (match_dup 3))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops[2], label;
|
||
|
||
label = gen_label_rtx ();
|
||
|
||
output_asm_insn (\"cld\", operands);
|
||
output_asm_insn (AS2 (xor%L0,%0,%0), operands);
|
||
output_asm_insn (\"repz\;cmps%B2\", operands);
|
||
output_asm_insn (\"je %l0\", &label);
|
||
|
||
xops[0] = operands[0];
|
||
xops[1] = const1_rtx;
|
||
output_asm_insn (AS2 (sbb%L0,%0,%0), xops);
|
||
if (QI_REG_P (xops[0]))
|
||
output_asm_insn (AS2 (or%B0,%1,%b0), xops);
|
||
else
|
||
output_asm_insn (AS2 (or%L0,%1,%0), xops);
|
||
|
||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (label));
|
||
RET;
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (cc0)
|
||
(compare:SI (mem:BLK (match_operand:SI 0 "address_operand" "S"))
|
||
(mem:BLK (match_operand:SI 1 "address_operand" "D"))))
|
||
(use (match_operand:SI 2 "register_operand" "c"))
|
||
(use (match_operand:SI 3 "immediate_operand" "i"))
|
||
(clobber (match_dup 0))
|
||
(clobber (match_dup 1))
|
||
(clobber (match_dup 2))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops[2];
|
||
|
||
cc_status.flags |= CC_NOT_SIGNED;
|
||
|
||
xops[0] = gen_rtx_REG (QImode, 0);
|
||
xops[1] = CONST0_RTX (QImode);
|
||
|
||
output_asm_insn (\"cld\", operands);
|
||
output_asm_insn (AS2 (test%B0,%1,%0), xops);
|
||
return \"repz\;cmps%B2\";
|
||
}")
|
||
|
||
|
||
;; Note, you cannot optimize away the branch following the bsfl by assuming
|
||
;; that the destination is not modified if the input is 0, since not all
|
||
;; x86 implementations do this.
|
||
|
||
(define_expand "ffssi2"
|
||
[(set (match_operand:SI 0 "general_operand" "")
|
||
(ffs:SI (match_operand:SI 1 "general_operand" "")))]
|
||
""
|
||
"
|
||
{
|
||
rtx label = gen_label_rtx (), temp = gen_reg_rtx (SImode);
|
||
|
||
emit_insn (gen_ffssi_1 (temp, operands[1]));
|
||
emit_cmp_insn (operands[1], const0_rtx, NE, NULL_RTX, SImode, 0, 0);
|
||
emit_jump_insn (gen_bne (label));
|
||
emit_move_insn (temp, constm1_rtx);
|
||
emit_label (label);
|
||
temp = expand_binop (SImode, add_optab, temp, const1_rtx,
|
||
operands[0], 0, OPTAB_WIDEN);
|
||
|
||
if (temp != operands[0])
|
||
emit_move_insn (operands[0], temp);
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "ffssi_1"
|
||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||
(unspec:SI [(match_operand:SI 1 "nonimmediate_operand" "rm")] 5))]
|
||
""
|
||
"* return AS2 (bsf%L0,%1,%0);")
|
||
|
||
(define_expand "ffshi2"
|
||
[(set (match_operand:SI 0 "general_operand" "")
|
||
(ffs:HI (match_operand:HI 1 "general_operand" "")))]
|
||
""
|
||
"
|
||
{
|
||
rtx label = gen_label_rtx (), temp = gen_reg_rtx (HImode);
|
||
|
||
emit_insn (gen_ffshi_1 (temp, operands[1]));
|
||
emit_cmp_insn (operands[1], const0_rtx, NE, NULL_RTX, HImode, 0, 0);
|
||
emit_jump_insn (gen_bne (label));
|
||
emit_move_insn (temp, constm1_rtx);
|
||
emit_label (label);
|
||
temp = expand_binop (HImode, add_optab, temp, const1_rtx,
|
||
operands[0], 0, OPTAB_WIDEN);
|
||
|
||
if (temp != operands[0])
|
||
emit_move_insn (operands[0], temp);
|
||
DONE;
|
||
}")
|
||
|
||
(define_insn "ffshi_1"
|
||
[(set (match_operand:HI 0 "register_operand" "=r")
|
||
(unspec:HI [(match_operand:SI 1 "nonimmediate_operand" "rm")] 5))]
|
||
""
|
||
"* return AS2 (bsf%W0,%1,%0);")
|
||
|
||
;; These patterns match the binary 387 instructions for addM3, subM3,
|
||
;; mulM3 and divM3. There are three patterns for each of DFmode and
|
||
;; SFmode. The first is the normal insn, the second the same insn but
|
||
;; with one operand a conversion, and the third the same insn but with
|
||
;; the other operand a conversion.
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f,f")
|
||
(match_operator:DF 3 "binary_387_op"
|
||
[(match_operand:DF 1 "nonimmediate_operand" "0,fm")
|
||
(match_operand:DF 2 "nonimmediate_operand" "fm,0")]))]
|
||
"TARGET_80387"
|
||
"* return output_387_binary_op (insn, operands);"
|
||
[(set (attr "type")
|
||
(cond [(match_operand:DF 3 "is_mul" "")
|
||
(const_string "fpmul")
|
||
(match_operand:DF 3 "is_div" "")
|
||
(const_string "fpdiv")
|
||
]
|
||
(const_string "fpop")
|
||
)
|
||
)])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f,f")
|
||
(match_operator:XF 3 "binary_387_op"
|
||
[(match_operand:XF 1 "register_operand" "0,f")
|
||
(match_operand:XF 2 "register_operand" "f,0")]))]
|
||
"TARGET_80387"
|
||
"* return output_387_binary_op (insn, operands);"
|
||
[(set (attr "type")
|
||
(cond [(match_operand:DF 3 "is_mul" "")
|
||
(const_string "fpmul")
|
||
(match_operand:DF 3 "is_div" "")
|
||
(const_string "fpdiv")
|
||
]
|
||
(const_string "fpop")
|
||
)
|
||
)])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f,f")
|
||
(match_operator:XF 3 "binary_387_op"
|
||
[(float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
|
||
(match_operand:XF 2 "register_operand" "0,f")]))]
|
||
"TARGET_80387"
|
||
"* return output_387_binary_op (insn, operands);"
|
||
[(set (attr "type")
|
||
(cond [(match_operand:DF 3 "is_mul" "")
|
||
(const_string "fpmul")
|
||
(match_operand:DF 3 "is_div" "")
|
||
(const_string "fpdiv")
|
||
]
|
||
(const_string "fpop")
|
||
)
|
||
)])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f,f")
|
||
(match_operator:XF 3 "binary_387_op"
|
||
[(match_operand:XF 1 "register_operand" "0,f")
|
||
(float_extend:XF
|
||
(match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
|
||
"TARGET_80387"
|
||
"* return output_387_binary_op (insn, operands);"
|
||
[(set (attr "type")
|
||
(cond [(match_operand:DF 3 "is_mul" "")
|
||
(const_string "fpmul")
|
||
(match_operand:DF 3 "is_div" "")
|
||
(const_string "fpdiv")
|
||
]
|
||
(const_string "fpop")
|
||
)
|
||
)])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f,f")
|
||
(match_operator:DF 3 "binary_387_op"
|
||
[(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
|
||
(match_operand:DF 2 "register_operand" "0,f")]))]
|
||
"TARGET_80387"
|
||
"* return output_387_binary_op (insn, operands);"
|
||
[(set (attr "type")
|
||
(cond [(match_operand:DF 3 "is_mul" "")
|
||
(const_string "fpmul")
|
||
(match_operand:DF 3 "is_div" "")
|
||
(const_string "fpdiv")
|
||
]
|
||
(const_string "fpop")
|
||
)
|
||
)])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f,f")
|
||
(match_operator:DF 3 "binary_387_op"
|
||
[(match_operand:DF 1 "register_operand" "0,f")
|
||
(float_extend:DF
|
||
(match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
|
||
"TARGET_80387"
|
||
"* return output_387_binary_op (insn, operands);"
|
||
[(set (attr "type")
|
||
(cond [(match_operand:DF 3 "is_mul" "")
|
||
(const_string "fpmul")
|
||
(match_operand:DF 3 "is_div" "")
|
||
(const_string "fpdiv")
|
||
]
|
||
(const_string "fpop")
|
||
)
|
||
)])
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
||
(match_operator:SF 3 "binary_387_op"
|
||
[(match_operand:SF 1 "nonimmediate_operand" "0,fm")
|
||
(match_operand:SF 2 "nonimmediate_operand" "fm,0")]))]
|
||
"TARGET_80387"
|
||
"* return output_387_binary_op (insn, operands);"
|
||
[(set (attr "type")
|
||
(cond [(match_operand:DF 3 "is_mul" "")
|
||
(const_string "fpmul")
|
||
(match_operand:DF 3 "is_div" "")
|
||
(const_string "fpdiv")
|
||
]
|
||
(const_string "fpop")
|
||
)
|
||
)])
|
||
|
||
(define_expand "strlensi"
|
||
[(parallel [(set (match_dup 4)
|
||
(unspec:SI [(mem:BLK (match_operand:BLK 1 "general_operand" ""))
|
||
(match_operand:QI 2 "immediate_operand" "")
|
||
(match_operand:SI 3 "immediate_operand" "")] 0))
|
||
(clobber (match_dup 1))])
|
||
(set (match_dup 5)
|
||
(not:SI (match_dup 4)))
|
||
(set (match_operand:SI 0 "register_operand" "")
|
||
(plus:SI (match_dup 5)
|
||
(const_int -1)))]
|
||
""
|
||
"
|
||
{
|
||
if (TARGET_UNROLL_STRLEN && operands[2] == const0_rtx && optimize > 1)
|
||
{
|
||
rtx address;
|
||
rtx scratch;
|
||
|
||
/* well it seems that some optimizer does not combine a call like
|
||
foo(strlen(bar), strlen(bar));
|
||
when the move and the subtraction is done here. It does calculate
|
||
the length just once when these instructions are done inside of
|
||
output_strlen_unroll(). But I think since &bar[strlen(bar)] is
|
||
often used and I use one fewer register for the lifetime of
|
||
output_strlen_unroll() this is better. */
|
||
scratch = gen_reg_rtx (SImode);
|
||
address = force_reg (SImode, XEXP (operands[1], 0));
|
||
|
||
/* move address to scratch-register
|
||
this is done here because the i586 can do the following and
|
||
in the same cycle with the following move. */
|
||
if (GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[3]) < 4)
|
||
emit_insn (gen_movsi (scratch, address));
|
||
|
||
emit_insn (gen_movsi (operands[0], address));
|
||
|
||
if(TARGET_USE_Q_REG)
|
||
emit_insn (gen_strlensi_unroll5 (operands[0],
|
||
operands[3],
|
||
scratch,
|
||
operands[0]));
|
||
else
|
||
emit_insn (gen_strlensi_unroll4 (operands[0],
|
||
operands[3],
|
||
scratch,
|
||
operands[0]));
|
||
|
||
/* gen_strlensi_unroll[45] returns the address of the zero
|
||
at the end of the string, like memchr(), so compute the
|
||
length by subtracting the startaddress. */
|
||
emit_insn (gen_subsi3 (operands[0], operands[0], address));
|
||
DONE;
|
||
}
|
||
|
||
operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
|
||
operands[4] = gen_reg_rtx (SImode);
|
||
operands[5] = gen_reg_rtx (SImode);
|
||
}")
|
||
|
||
;; It might seem that operands 0 & 1 could use predicate register_operand.
|
||
;; But strength reduction might offset the MEM expression. So we let
|
||
;; reload put the address into %edi.
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "register_operand" "=&c")
|
||
(unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "D"))
|
||
(match_operand:QI 2 "immediate_operand" "a")
|
||
(match_operand:SI 3 "immediate_operand" "i")] 0))
|
||
(clobber (match_dup 1))]
|
||
""
|
||
"*
|
||
{
|
||
rtx xops[2];
|
||
|
||
xops[0] = operands[0];
|
||
xops[1] = constm1_rtx;
|
||
output_asm_insn (\"cld\", operands);
|
||
output_asm_insn (AS2 (mov%L0,%1,%0), xops);
|
||
return \"repnz\;scas%B2\";
|
||
}")
|
||
|
||
/* Conditional move define_insns. */
|
||
|
||
(define_expand "movsicc"
|
||
[(set (match_operand:SI 0 "register_operand" "")
|
||
(if_then_else:SI (match_operand 1 "comparison_operator" "")
|
||
(match_operand:SI 2 "nonimmediate_operand" "")
|
||
(match_operand:SI 3 "nonimmediate_operand" "")))]
|
||
"TARGET_CMOVE"
|
||
"
|
||
{
|
||
if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
|
||
FAIL;
|
||
|
||
operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
|
||
GET_MODE (i386_compare_op0),
|
||
i386_compare_op0, i386_compare_op1);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
|
||
(if_then_else:SI (match_operator 1 "comparison_operator"
|
||
[(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
|
||
(match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
|
||
(match_operand:SI 4 "nonimmediate_operand" "rm,rm,0,0")
|
||
(match_operand:SI 5 "nonimmediate_operand" "0,0,rm,rm")))]
|
||
"TARGET_CMOVE"
|
||
"#")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
|
||
(if_then_else:SI (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "r,m,r,m")
|
||
(match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
|
||
(match_operand:SI 4 "nonimmediate_operand" "rm,rm,0,0")
|
||
(match_operand:SI 5 "nonimmediate_operand" "0,0,rm,rm")))]
|
||
"TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:SI 0 "register_operand" "")
|
||
(if_then_else:SI (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(const_int 0)])
|
||
(match_operand:SI 3 "nonimmediate_operand" "")
|
||
(match_operand:SI 4 "nonimmediate_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0)
|
||
(match_dup 2))
|
||
(set (match_dup 0)
|
||
(if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 3) (match_dup 4)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:SI 0 "register_operand" "")
|
||
(if_then_else:SI (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(match_operand 3 "general_operand" "")])
|
||
(match_operand:SI 4 "nonimmediate_operand" "")
|
||
(match_operand:SI 5 "nonimmediate_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0) (compare (match_dup 2) (match_dup 3)))
|
||
(set (match_dup 0)
|
||
(if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 4) (match_dup 5)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SI 0 "register_operand" "=r,r")
|
||
(if_then_else:SI (match_operator 1 "comparison_operator"
|
||
[(cc0) (const_int 0)])
|
||
(match_operand:SI 2 "nonimmediate_operand" "rm,0")
|
||
(match_operand:SI 3 "nonimmediate_operand" "0,rm")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
"* return output_int_conditional_move (which_alternative, operands);")
|
||
|
||
(define_expand "movhicc"
|
||
[(set (match_operand:HI 0 "register_operand" "")
|
||
(if_then_else:HI (match_operand 1 "comparison_operator" "")
|
||
(match_operand:HI 2 "nonimmediate_operand" "")
|
||
(match_operand:HI 3 "nonimmediate_operand" "")))]
|
||
"TARGET_CMOVE"
|
||
"
|
||
{
|
||
if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
|
||
FAIL;
|
||
|
||
operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
|
||
GET_MODE (i386_compare_op0),
|
||
i386_compare_op0, i386_compare_op1);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
|
||
(if_then_else:HI (match_operator 1 "comparison_operator"
|
||
[(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
|
||
(match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
|
||
(match_operand:HI 4 "nonimmediate_operand" "rm,rm,0,0")
|
||
(match_operand:HI 5 "nonimmediate_operand" "0,0,rm,rm")))]
|
||
"TARGET_CMOVE"
|
||
"#")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
|
||
(if_then_else:HI (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "r,m,r,m")
|
||
(match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
|
||
(match_operand:HI 4 "nonimmediate_operand" "rm,rm,0,0")
|
||
(match_operand:HI 5 "nonimmediate_operand" "0,0,rm,rm")))]
|
||
"TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:HI 0 "register_operand" "")
|
||
(if_then_else:HI (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(const_int 0)])
|
||
(match_operand:HI 3 "nonimmediate_operand" "")
|
||
(match_operand:HI 4 "nonimmediate_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0)
|
||
(match_dup 2))
|
||
(set (match_dup 0)
|
||
(if_then_else:HI (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 3) (match_dup 4)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:HI 0 "register_operand" "")
|
||
(if_then_else:HI (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(match_operand 3 "general_operand" "")])
|
||
(match_operand:HI 4 "nonimmediate_operand" "")
|
||
(match_operand:HI 5 "nonimmediate_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0)
|
||
(compare (match_dup 2) (match_dup 3)))
|
||
(set (match_dup 0)
|
||
(if_then_else:HI (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 4) (match_dup 5)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:HI 0 "register_operand" "=r,r")
|
||
(if_then_else:HI (match_operator 1 "comparison_operator"
|
||
[(cc0) (const_int 0)])
|
||
(match_operand:HI 2 "nonimmediate_operand" "rm,0")
|
||
(match_operand:HI 3 "nonimmediate_operand" "0,rm")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
"* return output_int_conditional_move (which_alternative, operands);")
|
||
|
||
(define_expand "movsfcc"
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(if_then_else:SF (match_operand 1 "comparison_operator" "")
|
||
(match_operand:SF 2 "register_operand" "")
|
||
(match_operand:SF 3 "register_operand" "")))]
|
||
"TARGET_CMOVE"
|
||
"
|
||
{
|
||
rtx temp;
|
||
|
||
if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
|
||
FAIL;
|
||
|
||
/* The floating point conditional move instructions don't directly
|
||
support conditions resulting from a signed integer comparison. */
|
||
|
||
switch (GET_CODE (operands[1]))
|
||
{
|
||
case LT:
|
||
case LE:
|
||
case GE:
|
||
case GT:
|
||
temp = emit_store_flag (gen_reg_rtx (QImode),
|
||
GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1,
|
||
VOIDmode, 0, 0);
|
||
|
||
if (!temp)
|
||
FAIL;
|
||
|
||
operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx);
|
||
break;
|
||
|
||
default:
|
||
operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
|
||
GET_MODE (i386_compare_op0),
|
||
i386_compare_op0, i386_compare_op1);
|
||
break;
|
||
}
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "register_operand" "=f,f,f,f")
|
||
(if_then_else:SF (match_operator 1 "comparison_operator"
|
||
[(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
|
||
(match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
|
||
(match_operand:SF 4 "register_operand" "f,f,0,0")
|
||
(match_operand:SF 5 "register_operand" "0,0,f,f")))]
|
||
"TARGET_CMOVE
|
||
&& GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
|
||
&& GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
|
||
"#")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "register_operand" "=f,f,f,f")
|
||
(if_then_else:SF (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "r,m,r,m")
|
||
(match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
|
||
(match_operand:SF 4 "register_operand" "f,f,0,0")
|
||
(match_operand:SF 5 "register_operand" "0,0,f,f")))]
|
||
"TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT
|
||
&& GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
|
||
&& GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(if_then_else:SF (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(const_int 0)])
|
||
(match_operand:SF 3 "register_operand" "")
|
||
(match_operand:SF 4 "register_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0)
|
||
(match_dup 2))
|
||
(set (match_dup 0)
|
||
(if_then_else:SF (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 3) (match_dup 4)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:SF 0 "register_operand" "")
|
||
(if_then_else:SF (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(match_operand 3 "general_operand" "")])
|
||
(match_operand:SF 4 "register_operand" "")
|
||
(match_operand:SF 5 "register_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0) (compare (match_dup 2) (match_dup 3)))
|
||
(set (match_dup 0)
|
||
(if_then_else:SF (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 4) (match_dup 5)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
||
(if_then_else:SF (match_operator 1 "comparison_operator"
|
||
[(cc0) (const_int 0)])
|
||
(match_operand:SF 2 "register_operand" "f,0")
|
||
(match_operand:SF 3 "register_operand" "0,f")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
"* return output_fp_conditional_move (which_alternative, operands);")
|
||
|
||
(define_expand "movdfcc"
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(if_then_else:DF (match_operand 1 "comparison_operator" "")
|
||
(match_operand:DF 2 "register_operand" "")
|
||
(match_operand:DF 3 "register_operand" "")))]
|
||
"TARGET_CMOVE"
|
||
"
|
||
{
|
||
rtx temp;
|
||
|
||
if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
|
||
FAIL;
|
||
|
||
/* The floating point conditional move instructions don't directly
|
||
support conditions resulting from a signed integer comparison. */
|
||
|
||
switch (GET_CODE (operands[1]))
|
||
{
|
||
case LT:
|
||
case LE:
|
||
case GE:
|
||
case GT:
|
||
temp = emit_store_flag (gen_reg_rtx (QImode),
|
||
GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1,
|
||
VOIDmode, 0, 0);
|
||
|
||
if (!temp)
|
||
FAIL;
|
||
|
||
operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx);
|
||
break;
|
||
|
||
default:
|
||
operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
|
||
GET_MODE (i386_compare_op0),
|
||
i386_compare_op0, i386_compare_op1);
|
||
break;
|
||
}
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f,f,f,f")
|
||
(if_then_else:DF (match_operator 1 "comparison_operator"
|
||
[(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
|
||
(match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
|
||
(match_operand:DF 4 "register_operand" "f,f,0,0")
|
||
(match_operand:DF 5 "register_operand" "0,0,f,f")))]
|
||
"TARGET_CMOVE
|
||
&& GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
|
||
&& GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
|
||
"#")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f,f,f,f")
|
||
(if_then_else:DF (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "r,m,r,m")
|
||
(match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
|
||
(match_operand:DF 4 "register_operand" "f,f,0,0")
|
||
(match_operand:DF 5 "register_operand" "0,0,f,f")))]
|
||
"TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT
|
||
&& GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
|
||
&& GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(if_then_else:DF (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(const_int 0)])
|
||
(match_operand:DF 3 "register_operand" "")
|
||
(match_operand:DF 4 "register_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0)
|
||
(match_dup 2))
|
||
(set (match_dup 0)
|
||
(if_then_else:DF (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 3) (match_dup 4)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:DF 0 "register_operand" "")
|
||
(if_then_else:DF (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(match_operand 3 "general_operand" "")])
|
||
(match_operand:DF 4 "register_operand" "")
|
||
(match_operand:DF 5 "register_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0) (compare (match_dup 2) (match_dup 3)))
|
||
(set (match_dup 0)
|
||
(if_then_else:DF (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 4) (match_dup 5)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DF 0 "register_operand" "=f,f")
|
||
(if_then_else:DF (match_operator 1 "comparison_operator"
|
||
[(cc0) (const_int 0)])
|
||
(match_operand:DF 2 "register_operand" "f,0")
|
||
(match_operand:DF 3 "register_operand" "0,f")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
"* return output_fp_conditional_move (which_alternative, operands);")
|
||
|
||
(define_expand "movxfcc"
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(if_then_else:XF (match_operand 1 "comparison_operator" "")
|
||
(match_operand:XF 2 "register_operand" "")
|
||
(match_operand:XF 3 "register_operand" "")))]
|
||
"TARGET_CMOVE"
|
||
"
|
||
{
|
||
rtx temp;
|
||
|
||
if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
|
||
FAIL;
|
||
|
||
/* The floating point conditional move instructions don't directly
|
||
support conditions resulting from a signed integer comparison. */
|
||
|
||
switch (GET_CODE (operands[1]))
|
||
{
|
||
case LT:
|
||
case LE:
|
||
case GE:
|
||
case GT:
|
||
temp = emit_store_flag (gen_reg_rtx (QImode),
|
||
GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1,
|
||
VOIDmode, 0, 0);
|
||
|
||
if (!temp)
|
||
FAIL;
|
||
|
||
operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx);
|
||
break;
|
||
|
||
default:
|
||
operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
|
||
GET_MODE (i386_compare_op0),
|
||
i386_compare_op0, i386_compare_op1);
|
||
break;
|
||
}
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f,f,f,f")
|
||
(if_then_else:XF (match_operator 1 "comparison_operator"
|
||
[(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
|
||
(match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
|
||
(match_operand:XF 4 "register_operand" "f,f,0,0")
|
||
(match_operand:XF 5 "register_operand" "0,0,f,f")))]
|
||
"TARGET_CMOVE
|
||
&& GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
|
||
&& GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
|
||
"#")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f,f,f,f")
|
||
(if_then_else:XF (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "r,m,r,m")
|
||
(match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
|
||
(match_operand:XF 4 "register_operand" "f,f,0,0")
|
||
(match_operand:XF 5 "register_operand" "0,0,f,f")))]
|
||
"TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT
|
||
&& GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
|
||
&& GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(if_then_else:XF (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(const_int 0)])
|
||
(match_operand:XF 3 "register_operand" "")
|
||
(match_operand:XF 4 "register_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0)
|
||
(match_dup 2))
|
||
(set (match_dup 0)
|
||
(if_then_else:XF (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 3) (match_dup 4)))]
|
||
"")
|
||
|
||
(define_split
|
||
[(set (match_operand:XF 0 "register_operand" "")
|
||
(if_then_else:XF (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(match_operand 3 "general_operand" "")])
|
||
(match_operand:XF 4 "register_operand" "")
|
||
(match_operand:XF 5 "register_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0) (compare (match_dup 2) (match_dup 3)))
|
||
(set (match_dup 0)
|
||
(if_then_else:XF (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 4) (match_dup 5)))]
|
||
"")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:XF 0 "register_operand" "=f,f")
|
||
(if_then_else:XF (match_operator 1 "comparison_operator"
|
||
[(cc0) (const_int 0)])
|
||
(match_operand:XF 2 "register_operand" "f,0")
|
||
(match_operand:XF 3 "register_operand" "0,f")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
"* return output_fp_conditional_move (which_alternative, operands);")
|
||
|
||
(define_expand "movdicc"
|
||
[(set (match_operand:DI 0 "register_operand" "")
|
||
(if_then_else:DI (match_operand 1 "comparison_operator" "")
|
||
(match_operand:DI 2 "nonimmediate_operand" "")
|
||
(match_operand:DI 3 "nonimmediate_operand" "")))]
|
||
"TARGET_CMOVE"
|
||
"
|
||
{
|
||
if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
|
||
FAIL;
|
||
|
||
operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
|
||
GET_MODE (i386_compare_op0),
|
||
i386_compare_op0, i386_compare_op1);
|
||
}")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DI 0 "register_operand" "=&r,&r,&r,&r")
|
||
(if_then_else:DI (match_operator 1 "comparison_operator"
|
||
[(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
|
||
(match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
|
||
(match_operand:DI 4 "nonimmediate_operand" "ro,ro,0,0")
|
||
(match_operand:DI 5 "nonimmediate_operand" "0,0,ro,ro")))]
|
||
"TARGET_CMOVE"
|
||
"#")
|
||
|
||
(define_insn ""
|
||
[(set (match_operand:DI 0 "register_operand" "=&r,&r,&r,&r")
|
||
(if_then_else:DI (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "r,m,r,m")
|
||
(match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
|
||
(match_operand:DI 4 "nonimmediate_operand" "ro,ro,0,0")
|
||
(match_operand:DI 5 "nonimmediate_operand" "0,0,ro,ro")))]
|
||
"TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT"
|
||
"#")
|
||
|
||
(define_split
|
||
[(set (match_operand:DI 0 "register_operand" "")
|
||
(if_then_else:DI (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(const_int 0)])
|
||
(match_operand:DI 3 "nonimmediate_operand" "")
|
||
(match_operand:DI 4 "nonimmediate_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0)
|
||
(match_dup 2))
|
||
(set (match_dup 5)
|
||
(if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 7) (match_dup 9)))
|
||
(set (match_dup 6)
|
||
(if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 8) (match_dup 10)))]
|
||
"split_di (&operands[0], 1, &operands[5], &operands[6]);
|
||
split_di (&operands[3], 1, &operands[7], &operands[8]);
|
||
split_di (&operands[4], 1, &operands[9], &operands[10]);")
|
||
|
||
(define_split
|
||
[(set (match_operand:DI 0 "register_operand" "")
|
||
(if_then_else:DI (match_operator 1 "comparison_operator"
|
||
[(match_operand 2 "nonimmediate_operand" "")
|
||
(match_operand 3 "general_operand" "")])
|
||
(match_operand:DI 4 "nonimmediate_operand" "")
|
||
(match_operand:DI 5 "nonimmediate_operand" "")))]
|
||
"TARGET_CMOVE && reload_completed"
|
||
[(set (cc0) (compare (match_dup 2) (match_dup 3)))
|
||
(set (match_dup 6)
|
||
(if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 8) (match_dup 10)))
|
||
(set (match_dup 7)
|
||
(if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
|
||
(match_dup 9) (match_dup 11)))]
|
||
"split_di (&operands[0], 1, &operands[6], &operands[7]);
|
||
split_di (&operands[4], 1, &operands[8], &operands[9]);
|
||
split_di (&operands[5], 1, &operands[10], &operands[11]);")
|
||
|
||
(define_insn "strlensi_unroll"
|
||
[(set (match_operand:SI 0 "register_operand" "=&r,&r")
|
||
(unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "r,r"))
|
||
(match_operand:SI 2 "immediate_operand" "i,i")] 0))
|
||
(clobber (match_scratch:SI 3 "=&q,&r"))]
|
||
"optimize > 1"
|
||
"* return output_strlen_unroll (operands);")
|
||
|
||
;; the only difference between the following patterns is the register preference
|
||
;; on a pentium using a q-register saves one clock cycle per 4 characters
|
||
|
||
(define_insn "strlensi_unroll4"
|
||
[(set (match_operand:SI 0 "register_operand" "=r,r")
|
||
(unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0,0"))
|
||
(match_operand:SI 1 "immediate_operand" "i,i")
|
||
(match_operand:SI 2 "register_operand" "+q,!r")] 0))
|
||
(clobber (match_dup 2))]
|
||
"(TARGET_USE_ANY_REG && optimize > 1)"
|
||
"* return output_strlen_unroll (operands);")
|
||
|
||
(define_insn "strlensi_unroll5"
|
||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||
(unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0"))
|
||
(match_operand:SI 1 "immediate_operand" "i")
|
||
(match_operand:SI 2 "register_operand" "+q")] 0))
|
||
(clobber (match_dup 2))]
|
||
"(TARGET_USE_Q_REG && optimize > 1)"
|
||
"* return output_strlen_unroll (operands);"
|
||
)
|
||
|
||
(define_insn "allocate_stack_worker"
|
||
[(unspec:SI [(match_operand:SI 0 "register_operand" "a")] 3)
|
||
(set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 0)))
|
||
(clobber (match_dup 0))]
|
||
"TARGET_STACK_PROBE"
|
||
"* return AS1(call,__alloca);"
|
||
[(set_attr "memory" "none")])
|
||
|
||
(define_expand "allocate_stack"
|
||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||
(minus:SI (reg:SI 7) (match_operand:SI 1 "general_operand" "")))
|
||
(set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 1)))]
|
||
"TARGET_STACK_PROBE"
|
||
"
|
||
{
|
||
#ifdef CHECK_STACK_LIMIT
|
||
if (GET_CODE (operands[1]) == CONST_INT
|
||
&& INTVAL (operands[1]) < CHECK_STACK_LIMIT)
|
||
emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
|
||
operands[1]));
|
||
else
|
||
#endif
|
||
emit_insn (gen_allocate_stack_worker (copy_to_mode_reg (SImode,
|
||
operands[1])));
|
||
|
||
emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
|
||
DONE;
|
||
}")
|
||
|
||
(define_expand "exception_receiver"
|
||
[(const_int 0)]
|
||
"flag_pic"
|
||
"
|
||
{
|
||
load_pic_register (1);
|
||
DONE;
|
||
}")
|
||
|
||
(define_expand "builtin_setjmp_receiver"
|
||
[(label_ref (match_operand 0 "" ""))]
|
||
"flag_pic"
|
||
"
|
||
{
|
||
load_pic_register (1);
|
||
DONE;
|
||
}")
|