aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config/pa/pa.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/config/pa/pa.md')
-rw-r--r--gcc-4.9/gcc/config/pa/pa.md9855
1 files changed, 9855 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/config/pa/pa.md b/gcc-4.9/gcc/config/pa/pa.md
new file mode 100644
index 000000000..e55d0b86b
--- /dev/null
+++ b/gcc-4.9/gcc/config/pa/pa.md
@@ -0,0 +1,9855 @@
+;;- Machine description for HP PA-RISC architecture for GCC compiler
+;; Copyright (C) 1992-2014 Free Software Foundation, Inc.
+;; Contributed by the Center for Software Science at the University
+;; of Utah.
+
+;; This file is part of GCC.
+
+;; GCC 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 3, or (at your option)
+;; any later version.
+
+;; GCC 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 GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; This machine description is inspired by sparc.md and to a lesser
+;; extent mips.md.
+
+;; Possible improvements:
+;;
+;; * With PA1.1, most computational instructions can conditionally nullify
+;; the execution of the following instruction. A nullified instruction
+;; does not cause the instruction pipeline to stall, making it a very
+;; efficient alternative to e.g. branching or conditional moves.
+;;
+;; Nullification is performed conditionally based on the outcome of a
+;; test specified in the opcode. The test result is stored in PSW[N]
+;; and can only be used to nullify the instruction following immediately
+;; after the test. For example:
+;;
+;; ldi 10,%r26
+;; ldi 5,%r25
+;; sub,< %r26,%r25,%r28
+;; sub %r28,%r25,%r28 ; %r28 == 0
+;; sub,> %r26,%r25,%r29
+;; sub %r29,%r25,%r29 ; %r29 == 5
+;;
+;; This could be tricky to implement because the result of the test has
+;; to be propagated one instruction forward, which, in the worst case,
+;; would involve (1) adding a fake register for PSW[N]; (2) adding the
+;; variants of the computational instructions that set or consume this
+;; fake register. The cond_exec infrastructure is probably not helpful
+;; for this.
+;;
+;; * PA-RISC includes a set of conventions for branch instruction usage
+;; to indicate whether a particular branch is more likely to be taken
+;; or not taken. For example, the prediction for CMPB instructions
+;; (CMPB,cond,n r1,r2,target) depends on the direction of the branch
+;; (forward or backward) and on the order of the operands:
+;;
+;; | branch | operand | branch |
+;; | direction | compare | prediction |
+;; +-----------+----------+------------+
+;; | backward | r1 < r2 | taken |
+;; | backward | r1 >= r2 | not taken |
+;; | forward | r1 < r2 | not taken |
+;; | forward | r1 >= r2 | taken |
+;;
+;; By choosing instructions and operand order carefully, the compiler
+;; could give the CPU branch predictor some help.
+;;
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+;; Uses of UNSPEC in this file:
+
+(define_c_enum "unspec"
+ [UNSPEC_CFFC ; canonicalize_funcptr_for_compare
+ UNSPEC_GOTO ; indirect_goto
+ UNSPEC_DLTIND14R
+ UNSPEC_TP
+ UNSPEC_TLSGD
+ UNSPEC_TLSLDM
+ UNSPEC_TLSLDO
+ UNSPEC_TLSLDBASE
+ UNSPEC_TLSIE
+ UNSPEC_TLSLE
+ UNSPEC_TLSGD_PIC
+ UNSPEC_TLSLDM_PIC
+ UNSPEC_TLSIE_PIC
+ ])
+
+;; UNSPEC_VOLATILE:
+
+(define_c_enum "unspecv"
+ [UNSPECV_BLOCKAGE ; blockage
+ UNSPECV_DCACHE ; dcacheflush
+ UNSPECV_ICACHE ; icacheflush
+ UNSPECV_OPC ; outline_prologue_call
+ UNSPECV_OEC ; outline_epilogue_call
+ UNSPECV_LONGJMP ; builtin_longjmp
+ ])
+
+;; Maximum pc-relative branch offsets.
+
+;; These numbers are a bit smaller than the maximum allowable offsets
+;; so that a few instructions may be inserted before the actual branch.
+
+(define_constants
+ [(MAX_12BIT_OFFSET 8184) ; 12-bit branch
+ (MAX_17BIT_OFFSET 262100) ; 17-bit branch
+ ])
+
+;; Mode and code iterators
+
+;; This mode iterator allows :P to be used for patterns that operate on
+;; pointer-sized quantities. Exactly one of the two alternatives will match.
+(define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
+
+;; This attribute defines the condition prefix for word and double word
+;; add, compare, subtract and logical instructions.
+(define_mode_attr dwc [(SI "") (DI "*")])
+
+;; Insn type. Used to default other attribute values.
+
+;; type "unary" insns have one input operand (1) and one output operand (0)
+;; type "binary" insns have two input operands (1,2) and one output (0)
+
+(define_attr "type"
+ "move,unary,binary,shift,nullshift,compare,load,store,uncond_branch,branch,cbranch,fbranch,call,sibcall,dyncall,fpload,fpstore,fpalu,fpcc,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,multi,milli,sh_func_adrs,parallel_branch,fpstore_load,store_fpload"
+ (const_string "binary"))
+
+(define_attr "pa_combine_type"
+ "fmpy,faddsub,uncond_branch,addmove,none"
+ (const_string "none"))
+
+;; Processor type (for scheduling, not code generation) -- this attribute
+;; must exactly match the processor_type enumeration in pa.h.
+;;
+;; FIXME: Add 800 scheduling for completeness?
+
+(define_attr "cpu" "700,7100,7100LC,7200,7300,8000" (const (symbol_ref "pa_cpu_attr")))
+
+;; Length (in # of bytes).
+(define_attr "length" ""
+ (cond [(eq_attr "type" "load,fpload")
+ (if_then_else (match_operand 1 "symbolic_memory_operand" "")
+ (const_int 8) (const_int 4))
+
+ (eq_attr "type" "store,fpstore")
+ (if_then_else (match_operand 0 "symbolic_memory_operand" "")
+ (const_int 8) (const_int 4))
+
+ (eq_attr "type" "binary,shift,nullshift")
+ (if_then_else (match_operand 2 "arith14_operand" "")
+ (const_int 4) (const_int 12))
+
+ (eq_attr "type" "move,unary,shift,nullshift")
+ (if_then_else (match_operand 1 "arith14_operand" "")
+ (const_int 4) (const_int 8))]
+
+ (const_int 4)))
+
+(define_asm_attributes
+ [(set_attr "length" "4")
+ (set_attr "type" "multi")])
+
+;; Attributes for instruction and branch scheduling
+
+;; For conditional branches. Frame related instructions are not allowed
+;; because they confuse the unwind support.
+(define_attr "in_branch_delay" "false,true"
+ (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,sibcall,dyncall,multi,milli,sh_func_adrs,parallel_branch")
+ (eq_attr "length" "4")
+ (not (match_test "RTX_FRAME_RELATED_P (insn)")))
+ (const_string "true")
+ (const_string "false")))
+
+;; Disallow instructions which use the FPU since they will tie up the FPU
+;; even if the instruction is nullified.
+(define_attr "in_nullified_branch_delay" "false,true"
+ (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,sibcall,dyncall,multi,milli,sh_func_adrs,fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,parallel_branch")
+ (eq_attr "length" "4")
+ (not (match_test "RTX_FRAME_RELATED_P (insn)")))
+ (const_string "true")
+ (const_string "false")))
+
+;; For calls and millicode calls. Allow unconditional branches in the
+;; delay slot.
+(define_attr "in_call_delay" "false,true"
+ (cond [(and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,sibcall,dyncall,multi,milli,sh_func_adrs,parallel_branch")
+ (eq_attr "length" "4")
+ (not (match_test "RTX_FRAME_RELATED_P (insn)")))
+ (const_string "true")
+ (eq_attr "type" "uncond_branch")
+ (if_then_else (match_test "TARGET_JUMP_IN_DELAY")
+ (const_string "true")
+ (const_string "false"))]
+ (const_string "false")))
+
+
+;; Call delay slot description.
+(define_delay (eq_attr "type" "call")
+ [(eq_attr "in_call_delay" "true") (nil) (nil)])
+
+;; Sibcall delay slot description.
+(define_delay (eq_attr "type" "sibcall")
+ [(eq_attr "in_call_delay" "true") (nil) (nil)])
+
+;; Millicode call delay slot description.
+(define_delay (eq_attr "type" "milli")
+ [(eq_attr "in_call_delay" "true") (nil) (nil)])
+
+;; Return and other similar instructions.
+(define_delay (eq_attr "type" "branch,parallel_branch")
+ [(eq_attr "in_branch_delay" "true") (nil) (nil)])
+
+;; Floating point conditional branch delay slot description.
+(define_delay (eq_attr "type" "fbranch")
+ [(eq_attr "in_branch_delay" "true")
+ (eq_attr "in_nullified_branch_delay" "true")
+ (nil)])
+
+;; Integer conditional branch delay slot description.
+;; Nullification of conditional branches on the PA is dependent on the
+;; direction of the branch. Forward branches nullify true and
+;; backward branches nullify false. If the direction is unknown
+;; then nullification is not allowed.
+(define_delay (eq_attr "type" "cbranch")
+ [(eq_attr "in_branch_delay" "true")
+ (and (eq_attr "in_nullified_branch_delay" "true")
+ (attr_flag "forward"))
+ (and (eq_attr "in_nullified_branch_delay" "true")
+ (attr_flag "backward"))])
+
+(define_delay (and (eq_attr "type" "uncond_branch")
+ (not (match_test "pa_following_call (insn)")))
+ [(eq_attr "in_branch_delay" "true") (nil) (nil)])
+
+;; Memory. Disregarding Cache misses, the Mustang memory times are:
+;; load: 2, fpload: 3
+;; store, fpstore: 3, no D-cache operations should be scheduled.
+
+;; The Timex (aka 700) has two floating-point units: ALU, and MUL/DIV/SQRT.
+;; Timings:
+;; Instruction Time Unit Minimum Distance (unit contention)
+;; fcpy 3 ALU 2
+;; fabs 3 ALU 2
+;; fadd 3 ALU 2
+;; fsub 3 ALU 2
+;; fcmp 3 ALU 2
+;; fcnv 3 ALU 2
+;; fmpyadd 3 ALU,MPY 2
+;; fmpysub 3 ALU,MPY 2
+;; fmpycfxt 3 ALU,MPY 2
+;; fmpy 3 MPY 2
+;; fmpyi 3 MPY 2
+;; fdiv,sgl 10 MPY 10
+;; fdiv,dbl 12 MPY 12
+;; fsqrt,sgl 14 MPY 14
+;; fsqrt,dbl 18 MPY 18
+;;
+;; We don't model fmpyadd/fmpysub properly as those instructions
+;; keep both the FP ALU and MPY units busy. Given that these
+;; processors are obsolete, I'm not going to spend the time to
+;; model those instructions correctly.
+
+(define_automaton "pa700")
+(define_cpu_unit "dummy_700,mem_700,fpalu_700,fpmpy_700" "pa700")
+
+(define_insn_reservation "W0" 4
+ (and (eq_attr "type" "fpcc")
+ (eq_attr "cpu" "700"))
+ "fpalu_700*2")
+
+(define_insn_reservation "W1" 3
+ (and (eq_attr "type" "fpalu")
+ (eq_attr "cpu" "700"))
+ "fpalu_700*2")
+
+(define_insn_reservation "W2" 3
+ (and (eq_attr "type" "fpmulsgl,fpmuldbl")
+ (eq_attr "cpu" "700"))
+ "fpmpy_700*2")
+
+(define_insn_reservation "W3" 10
+ (and (eq_attr "type" "fpdivsgl")
+ (eq_attr "cpu" "700"))
+ "fpmpy_700*10")
+
+(define_insn_reservation "W4" 12
+ (and (eq_attr "type" "fpdivdbl")
+ (eq_attr "cpu" "700"))
+ "fpmpy_700*12")
+
+(define_insn_reservation "W5" 14
+ (and (eq_attr "type" "fpsqrtsgl")
+ (eq_attr "cpu" "700"))
+ "fpmpy_700*14")
+
+(define_insn_reservation "W6" 18
+ (and (eq_attr "type" "fpsqrtdbl")
+ (eq_attr "cpu" "700"))
+ "fpmpy_700*18")
+
+(define_insn_reservation "W7" 2
+ (and (eq_attr "type" "load")
+ (eq_attr "cpu" "700"))
+ "mem_700")
+
+(define_insn_reservation "W8" 2
+ (and (eq_attr "type" "fpload")
+ (eq_attr "cpu" "700"))
+ "mem_700")
+
+(define_insn_reservation "W9" 3
+ (and (eq_attr "type" "store")
+ (eq_attr "cpu" "700"))
+ "mem_700*3")
+
+(define_insn_reservation "W10" 3
+ (and (eq_attr "type" "fpstore")
+ (eq_attr "cpu" "700"))
+ "mem_700*3")
+
+(define_insn_reservation "W11" 5
+ (and (eq_attr "type" "fpstore_load")
+ (eq_attr "cpu" "700"))
+ "mem_700*5")
+
+(define_insn_reservation "W12" 6
+ (and (eq_attr "type" "store_fpload")
+ (eq_attr "cpu" "700"))
+ "mem_700*6")
+
+(define_insn_reservation "W13" 1
+ (and (eq_attr "type" "!fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,load,fpload,store,fpstore,fpstore_load,store_fpload")
+ (eq_attr "cpu" "700"))
+ "dummy_700")
+
+;; We have a bypass for all computations in the FP unit which feed an
+;; FP store as long as the sizes are the same.
+(define_bypass 2 "W1,W2" "W10,W11" "pa_fpstore_bypass_p")
+(define_bypass 9 "W3" "W10,W11" "pa_fpstore_bypass_p")
+(define_bypass 11 "W4" "W10,W11" "pa_fpstore_bypass_p")
+(define_bypass 13 "W5" "W10,W11" "pa_fpstore_bypass_p")
+(define_bypass 17 "W6" "W10,W11" "pa_fpstore_bypass_p")
+
+;; We have an "anti-bypass" for FP loads which feed an FP store.
+(define_bypass 4 "W8,W12" "W10,W11" "pa_fpstore_bypass_p")
+
+;; Function units for the 7100 and 7150. The 7100/7150 can dual-issue
+;; floating point computations with non-floating point computations (fp loads
+;; and stores are not fp computations).
+;;
+;; Memory. Disregarding Cache misses, memory loads take two cycles; stores also
+;; take two cycles, during which no Dcache operations should be scheduled.
+;; Any special cases are handled in pa_adjust_cost. The 7100, 7150 and 7100LC
+;; all have the same memory characteristics if one disregards cache misses.
+;;
+;; The 7100/7150 has three floating-point units: ALU, MUL, and DIV.
+;; There's no value in modeling the ALU and MUL separately though
+;; since there can never be a functional unit conflict given the
+;; latency and issue rates for those units.
+;;
+;; Timings:
+;; Instruction Time Unit Minimum Distance (unit contention)
+;; fcpy 2 ALU 1
+;; fabs 2 ALU 1
+;; fadd 2 ALU 1
+;; fsub 2 ALU 1
+;; fcmp 2 ALU 1
+;; fcnv 2 ALU 1
+;; fmpyadd 2 ALU,MPY 1
+;; fmpysub 2 ALU,MPY 1
+;; fmpycfxt 2 ALU,MPY 1
+;; fmpy 2 MPY 1
+;; fmpyi 2 MPY 1
+;; fdiv,sgl 8 DIV 8
+;; fdiv,dbl 15 DIV 15
+;; fsqrt,sgl 8 DIV 8
+;; fsqrt,dbl 15 DIV 15
+
+(define_automaton "pa7100")
+(define_cpu_unit "i_7100, f_7100,fpmac_7100,fpdivsqrt_7100,mem_7100" "pa7100")
+
+(define_insn_reservation "X0" 2
+ (and (eq_attr "type" "fpcc,fpalu,fpmulsgl,fpmuldbl")
+ (eq_attr "cpu" "7100"))
+ "f_7100,fpmac_7100")
+
+(define_insn_reservation "X1" 8
+ (and (eq_attr "type" "fpdivsgl,fpsqrtsgl")
+ (eq_attr "cpu" "7100"))
+ "f_7100+fpdivsqrt_7100,fpdivsqrt_7100*7")
+
+(define_insn_reservation "X2" 15
+ (and (eq_attr "type" "fpdivdbl,fpsqrtdbl")
+ (eq_attr "cpu" "7100"))
+ "f_7100+fpdivsqrt_7100,fpdivsqrt_7100*14")
+
+(define_insn_reservation "X3" 2
+ (and (eq_attr "type" "load")
+ (eq_attr "cpu" "7100"))
+ "i_7100+mem_7100")
+
+(define_insn_reservation "X4" 2
+ (and (eq_attr "type" "fpload")
+ (eq_attr "cpu" "7100"))
+ "i_7100+mem_7100")
+
+(define_insn_reservation "X5" 2
+ (and (eq_attr "type" "store")
+ (eq_attr "cpu" "7100"))
+ "i_7100+mem_7100,mem_7100")
+
+(define_insn_reservation "X6" 2
+ (and (eq_attr "type" "fpstore")
+ (eq_attr "cpu" "7100"))
+ "i_7100+mem_7100,mem_7100")
+
+(define_insn_reservation "X7" 4
+ (and (eq_attr "type" "fpstore_load")
+ (eq_attr "cpu" "7100"))
+ "i_7100+mem_7100,mem_7100*3")
+
+(define_insn_reservation "X8" 4
+ (and (eq_attr "type" "store_fpload")
+ (eq_attr "cpu" "7100"))
+ "i_7100+mem_7100,mem_7100*3")
+
+(define_insn_reservation "X9" 1
+ (and (eq_attr "type" "!fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpsqrtsgl,fpdivdbl,fpsqrtdbl,load,fpload,store,fpstore,fpstore_load,store_fpload")
+ (eq_attr "cpu" "7100"))
+ "i_7100")
+
+;; We have a bypass for all computations in the FP unit which feed an
+;; FP store as long as the sizes are the same.
+(define_bypass 1 "X0" "X6,X7" "pa_fpstore_bypass_p")
+(define_bypass 7 "X1" "X6,X7" "pa_fpstore_bypass_p")
+(define_bypass 14 "X2" "X6,X7" "pa_fpstore_bypass_p")
+
+;; We have an "anti-bypass" for FP loads which feed an FP store.
+(define_bypass 3 "X4,X8" "X6,X7" "pa_fpstore_bypass_p")
+
+;; The 7100LC has three floating-point units: ALU, MUL, and DIV.
+;; There's no value in modeling the ALU and MUL separately though
+;; since there can never be a functional unit conflict that
+;; can be avoided given the latency, issue rates and mandatory
+;; one cycle cpu-wide lock for a double precision fp multiply.
+;;
+;; Timings:
+;; Instruction Time Unit Minimum Distance (unit contention)
+;; fcpy 2 ALU 1
+;; fabs 2 ALU 1
+;; fadd 2 ALU 1
+;; fsub 2 ALU 1
+;; fcmp 2 ALU 1
+;; fcnv 2 ALU 1
+;; fmpyadd,sgl 2 ALU,MPY 1
+;; fmpyadd,dbl 3 ALU,MPY 2
+;; fmpysub,sgl 2 ALU,MPY 1
+;; fmpysub,dbl 3 ALU,MPY 2
+;; fmpycfxt,sgl 2 ALU,MPY 1
+;; fmpycfxt,dbl 3 ALU,MPY 2
+;; fmpy,sgl 2 MPY 1
+;; fmpy,dbl 3 MPY 2
+;; fmpyi 3 MPY 2
+;; fdiv,sgl 8 DIV 8
+;; fdiv,dbl 15 DIV 15
+;; fsqrt,sgl 8 DIV 8
+;; fsqrt,dbl 15 DIV 15
+;;
+;; The PA7200 is just like the PA7100LC except that there is
+;; no store-store penalty.
+;;
+;; The PA7300 is just like the PA7200 except that there is
+;; no store-load penalty.
+;;
+;; Note there are some aspects of the 7100LC we are not modeling
+;; at the moment. I'll be reviewing the 7100LC scheduling info
+;; shortly and updating this description.
+;;
+;; load-load pairs
+;; store-store pairs
+;; other issue modeling
+
+(define_automaton "pa7100lc")
+(define_cpu_unit "i0_7100lc, i1_7100lc, f_7100lc" "pa7100lc")
+(define_cpu_unit "fpmac_7100lc" "pa7100lc")
+(define_cpu_unit "mem_7100lc" "pa7100lc")
+
+;; Double precision multiplies lock the entire CPU for one
+;; cycle. There is no way to avoid this lock and trying to
+;; schedule around the lock is pointless and thus there is no
+;; value in trying to model this lock.
+;;
+;; Not modeling the lock allows us to treat fp multiplies just
+;; like any other FP alu instruction. It allows for a smaller
+;; DFA and may reduce register pressure.
+(define_insn_reservation "Y0" 2
+ (and (eq_attr "type" "fpcc,fpalu,fpmulsgl,fpmuldbl")
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "f_7100lc,fpmac_7100lc")
+
+;; fp division and sqrt instructions lock the entire CPU for
+;; 7 cycles (single precision) or 14 cycles (double precision).
+;; There is no way to avoid this lock and trying to schedule
+;; around the lock is pointless and thus there is no value in
+;; trying to model this lock. Not modeling the lock allows
+;; for a smaller DFA and may reduce register pressure.
+(define_insn_reservation "Y1" 1
+ (and (eq_attr "type" "fpdivsgl,fpsqrtsgl,fpdivdbl,fpsqrtdbl")
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "f_7100lc")
+
+(define_insn_reservation "Y2" 2
+ (and (eq_attr "type" "load")
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "i1_7100lc+mem_7100lc")
+
+(define_insn_reservation "Y3" 2
+ (and (eq_attr "type" "fpload")
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "i1_7100lc+mem_7100lc")
+
+(define_insn_reservation "Y4" 2
+ (and (eq_attr "type" "store")
+ (eq_attr "cpu" "7100LC"))
+ "i1_7100lc+mem_7100lc,mem_7100lc")
+
+(define_insn_reservation "Y5" 2
+ (and (eq_attr "type" "fpstore")
+ (eq_attr "cpu" "7100LC"))
+ "i1_7100lc+mem_7100lc,mem_7100lc")
+
+(define_insn_reservation "Y6" 4
+ (and (eq_attr "type" "fpstore_load")
+ (eq_attr "cpu" "7100LC"))
+ "i1_7100lc+mem_7100lc,mem_7100lc*3")
+
+(define_insn_reservation "Y7" 4
+ (and (eq_attr "type" "store_fpload")
+ (eq_attr "cpu" "7100LC"))
+ "i1_7100lc+mem_7100lc,mem_7100lc*3")
+
+(define_insn_reservation "Y8" 1
+ (and (eq_attr "type" "shift,nullshift")
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "i1_7100lc")
+
+(define_insn_reservation "Y9" 1
+ (and (eq_attr "type" "!fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpsqrtsgl,fpdivdbl,fpsqrtdbl,load,fpload,store,fpstore,shift,nullshift")
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "(i0_7100lc|i1_7100lc)")
+
+;; The 7200 has a store-load penalty
+(define_insn_reservation "Y10" 2
+ (and (eq_attr "type" "store")
+ (eq_attr "cpu" "7200"))
+ "i1_7100lc,mem_7100lc")
+
+(define_insn_reservation "Y11" 2
+ (and (eq_attr "type" "fpstore")
+ (eq_attr "cpu" "7200"))
+ "i1_7100lc,mem_7100lc")
+
+(define_insn_reservation "Y12" 4
+ (and (eq_attr "type" "fpstore_load")
+ (eq_attr "cpu" "7200"))
+ "i1_7100lc,mem_7100lc,i1_7100lc+mem_7100lc")
+
+(define_insn_reservation "Y13" 4
+ (and (eq_attr "type" "store_fpload")
+ (eq_attr "cpu" "7200"))
+ "i1_7100lc,mem_7100lc,i1_7100lc+mem_7100lc")
+
+;; The 7300 has no penalty for store-store or store-load
+(define_insn_reservation "Y14" 2
+ (and (eq_attr "type" "store")
+ (eq_attr "cpu" "7300"))
+ "i1_7100lc")
+
+(define_insn_reservation "Y15" 2
+ (and (eq_attr "type" "fpstore")
+ (eq_attr "cpu" "7300"))
+ "i1_7100lc")
+
+(define_insn_reservation "Y16" 4
+ (and (eq_attr "type" "fpstore_load")
+ (eq_attr "cpu" "7300"))
+ "i1_7100lc,i1_7100lc+mem_7100lc")
+
+(define_insn_reservation "Y17" 4
+ (and (eq_attr "type" "store_fpload")
+ (eq_attr "cpu" "7300"))
+ "i1_7100lc,i1_7100lc+mem_7100lc")
+
+;; We have an "anti-bypass" for FP loads which feed an FP store.
+(define_bypass 3 "Y3,Y7,Y13,Y17" "Y5,Y6,Y11,Y12,Y15,Y16" "pa_fpstore_bypass_p")
+
+;; Scheduling for the PA8000 is somewhat different than scheduling for a
+;; traditional architecture.
+;;
+;; The PA8000 has a large (56) entry reorder buffer that is split between
+;; memory and non-memory operations.
+;;
+;; The PA8000 can issue two memory and two non-memory operations per cycle to
+;; the function units, with the exception of branches and multi-output
+;; instructions. The PA8000 can retire two non-memory operations per cycle
+;; and two memory operations per cycle, only one of which may be a store.
+;;
+;; Given the large reorder buffer, the processor can hide most latencies.
+;; According to HP, they've got the best results by scheduling for retirement
+;; bandwidth with limited latency scheduling for floating point operations.
+;; Latency for integer operations and memory references is ignored.
+;;
+;;
+;; We claim floating point operations have a 2 cycle latency and are
+;; fully pipelined, except for div and sqrt which are not pipelined and
+;; take from 17 to 31 cycles to complete.
+;;
+;; It's worth noting that there is no way to saturate all the functional
+;; units on the PA8000 as there is not enough issue bandwidth.
+
+(define_automaton "pa8000")
+(define_cpu_unit "inm0_8000, inm1_8000, im0_8000, im1_8000" "pa8000")
+(define_cpu_unit "rnm0_8000, rnm1_8000, rm0_8000, rm1_8000" "pa8000")
+(define_cpu_unit "store_8000" "pa8000")
+(define_cpu_unit "f0_8000, f1_8000" "pa8000")
+(define_cpu_unit "fdivsqrt0_8000, fdivsqrt1_8000" "pa8000")
+(define_reservation "inm_8000" "inm0_8000 | inm1_8000")
+(define_reservation "im_8000" "im0_8000 | im1_8000")
+(define_reservation "rnm_8000" "rnm0_8000 | rnm1_8000")
+(define_reservation "rm_8000" "rm0_8000 | rm1_8000")
+(define_reservation "f_8000" "f0_8000 | f1_8000")
+(define_reservation "fdivsqrt_8000" "fdivsqrt0_8000 | fdivsqrt1_8000")
+
+;; We can issue any two memops per cycle, but we can only retire
+;; one memory store per cycle. We assume that the reorder buffer
+;; will hide any memory latencies per HP's recommendation.
+(define_insn_reservation "Z0" 0
+ (and
+ (eq_attr "type" "load,fpload")
+ (eq_attr "cpu" "8000"))
+ "im_8000,rm_8000")
+
+(define_insn_reservation "Z1" 0
+ (and
+ (eq_attr "type" "store,fpstore")
+ (eq_attr "cpu" "8000"))
+ "im_8000,rm_8000+store_8000")
+
+(define_insn_reservation "Z2" 0
+ (and (eq_attr "type" "fpstore_load,store_fpload")
+ (eq_attr "cpu" "8000"))
+ "im_8000,rm_8000+store_8000,im_8000,rm_8000")
+
+;; We can issue and retire two non-memory operations per cycle with
+;; a few exceptions (branches). This group catches those we want
+;; to assume have zero latency.
+(define_insn_reservation "Z3" 0
+ (and
+ (eq_attr "type" "!load,fpload,store,fpstore,uncond_branch,branch,cbranch,fbranch,call,sibcall,dyncall,multi,milli,sh_func_adrs,parallel_branch,fpcc,fpalu,fpmulsgl,fpmuldbl,fpsqrtsgl,fpsqrtdbl,fpdivsgl,fpdivdbl,fpstore_load,store_fpload")
+ (eq_attr "cpu" "8000"))
+ "inm_8000,rnm_8000")
+
+;; Branches use both slots in the non-memory issue and
+;; retirement unit.
+(define_insn_reservation "Z4" 0
+ (and
+ (eq_attr "type" "uncond_branch,branch,cbranch,fbranch,call,sibcall,dyncall,multi,milli,sh_func_adrs,parallel_branch")
+ (eq_attr "cpu" "8000"))
+ "inm0_8000+inm1_8000,rnm0_8000+rnm1_8000")
+
+;; We partial latency schedule the floating point units.
+;; They can issue/retire two at a time in the non-memory
+;; units. We fix their latency at 2 cycles and they
+;; are fully pipelined.
+(define_insn_reservation "Z5" 1
+ (and
+ (eq_attr "type" "fpcc,fpalu,fpmulsgl,fpmuldbl")
+ (eq_attr "cpu" "8000"))
+ "inm_8000,f_8000,rnm_8000")
+
+;; The fdivsqrt units are not pipelined and have a very long latency.
+;; To keep the DFA from exploding, we do not show all the
+;; reservations for the divsqrt unit.
+(define_insn_reservation "Z6" 17
+ (and
+ (eq_attr "type" "fpdivsgl,fpsqrtsgl")
+ (eq_attr "cpu" "8000"))
+ "inm_8000,fdivsqrt_8000*6,rnm_8000")
+
+(define_insn_reservation "Z7" 31
+ (and
+ (eq_attr "type" "fpdivdbl,fpsqrtdbl")
+ (eq_attr "cpu" "8000"))
+ "inm_8000,fdivsqrt_8000*6,rnm_8000")
+
+;; Operand and operator predicates and constraints
+
+(include "predicates.md")
+(include "constraints.md")
+
+;; Atomic instructions
+
+;; All memory loads and stores access storage atomically except
+;; for one exception. The STORE BYTES, STORE DOUBLE BYTES, and
+;; doubleword loads and stores are not guaranteed to be atomic
+;; when referencing the I/O address space.
+
+;; Implement atomic DImode load using 64-bit floating point load and copy.
+
+(define_expand "atomic_loaddi"
+ [(match_operand:DI 0 "register_operand") ;; val out
+ (match_operand:DI 1 "memory_operand") ;; memory
+ (match_operand:SI 2 "const_int_operand")] ;; model
+ "!TARGET_64BIT && !TARGET_SOFT_FLOAT"
+{
+ enum memmodel model = (enum memmodel) INTVAL (operands[2]);
+ operands[1] = force_reg (SImode, XEXP (operands[1], 0));
+ operands[2] = gen_reg_rtx (DImode);
+ expand_mem_thread_fence (model);
+ emit_insn (gen_atomic_loaddi_1 (operands[0], operands[1], operands[2]));
+ if ((model & MEMMODEL_MASK) == MEMMODEL_SEQ_CST)
+ expand_mem_thread_fence (model);
+ DONE;
+})
+
+(define_insn "atomic_loaddi_1"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mem:DI (match_operand:SI 1 "register_operand" "r")))
+ (clobber (match_operand:DI 2 "register_operand" "=&f"))]
+ "!TARGET_64BIT && !TARGET_SOFT_FLOAT"
+ "{fldds|fldd} 0(%1),%2\;{fstds|fstd} %2,-16(%%sp)\;{ldws|ldw} -16(%%sp),%0\;{ldws|ldw} -12(%%sp),%R0"
+ [(set_attr "type" "move")
+ (set_attr "length" "16")])
+
+;; Implement atomic DImode store using copy and 64-bit floating point store.
+
+(define_expand "atomic_storedi"
+ [(match_operand:DI 0 "memory_operand") ;; memory
+ (match_operand:DI 1 "register_operand") ;; val out
+ (match_operand:SI 2 "const_int_operand")] ;; model
+ "!TARGET_64BIT && !TARGET_SOFT_FLOAT"
+{
+ enum memmodel model = (enum memmodel) INTVAL (operands[2]);
+ operands[0] = force_reg (SImode, XEXP (operands[0], 0));
+ operands[2] = gen_reg_rtx (DImode);
+ expand_mem_thread_fence (model);
+ emit_insn (gen_atomic_storedi_1 (operands[0], operands[1], operands[2]));
+ if ((model & MEMMODEL_MASK) == MEMMODEL_SEQ_CST)
+ expand_mem_thread_fence (model);
+ DONE;
+})
+
+(define_insn "atomic_storedi_1"
+ [(set (mem:DI (match_operand:SI 0 "register_operand" "r"))
+ (match_operand:DI 1 "register_operand" "r"))
+ (clobber (match_operand:DI 2 "register_operand" "=&f"))]
+ "!TARGET_64BIT && !TARGET_SOFT_FLOAT"
+ "{stws|stw} %1,-16(%%sp)\;{stws|stw} %R1,-12(%%sp)\;{fldds|fldd} -16(%%sp),%2\;{fstds|fstd} %2,0(%0)"
+ [(set_attr "type" "move")
+ (set_attr "length" "16")])
+
+;; Compare instructions.
+;; This controls RTL generation and register allocation.
+
+(define_insn ""
+ [(set (reg:CCFP 0)
+ (match_operator:CCFP 2 "comparison_operator"
+ [(match_operand:SF 0 "reg_or_0_operand" "fG")
+ (match_operand:SF 1 "reg_or_0_operand" "fG")]))]
+ "! TARGET_SOFT_FLOAT"
+ "fcmp,sgl,%Y2 %f0,%f1"
+ [(set_attr "length" "4")
+ (set_attr "type" "fpcc")])
+
+(define_insn ""
+ [(set (reg:CCFP 0)
+ (match_operator:CCFP 2 "comparison_operator"
+ [(match_operand:DF 0 "reg_or_0_operand" "fG")
+ (match_operand:DF 1 "reg_or_0_operand" "fG")]))]
+ "! TARGET_SOFT_FLOAT"
+ "fcmp,dbl,%Y2 %f0,%f1"
+ [(set_attr "length" "4")
+ (set_attr "type" "fpcc")])
+
+;; Provide a means to emit the movccfp0 and movccfp1 optimization
+;; placeholders. This is necessary in rare situations when a
+;; placeholder is re-emitted (see PR 8705).
+
+(define_expand "movccfp"
+ [(set (reg:CCFP 0)
+ (match_operand 0 "const_int_operand" ""))]
+ "! TARGET_SOFT_FLOAT"
+ "
+{
+ if ((unsigned HOST_WIDE_INT) INTVAL (operands[0]) > 1)
+ FAIL;
+}")
+
+;; The following patterns are optimization placeholders. In almost
+;; all cases, the user of the condition code will be simplified and the
+;; original condition code setting insn should be eliminated.
+
+(define_insn "*movccfp0"
+ [(set (reg:CCFP 0)
+ (const_int 0))]
+ "! TARGET_SOFT_FLOAT"
+ "fcmp,dbl,= %%fr0,%%fr0"
+ [(set_attr "length" "4")
+ (set_attr "type" "fpcc")])
+
+(define_insn "*movccfp1"
+ [(set (reg:CCFP 0)
+ (const_int 1))]
+ "! TARGET_SOFT_FLOAT"
+ "fcmp,dbl,!= %%fr0,%%fr0"
+ [(set_attr "length" "4")
+ (set_attr "type" "fpcc")])
+
+;; scc insns.
+
+(define_expand "cstoresi4"
+ [(set (match_operand:SI 0 "register_operand")
+ (match_operator:SI 1 "ordered_comparison_operator"
+ [(match_operand:SI 2 "reg_or_0_operand" "")
+ (match_operand:SI 3 "arith5_operand" "")]))]
+ "!TARGET_64BIT"
+ "")
+
+;; Instruction canonicalization puts immediate operands second, which
+;; is the reverse of what we want.
+
+(define_insn "scc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 3 "comparison_operator"
+ [(match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "arith11_operand" "rI")]))]
+ ""
+ "{com%I2clr|cmp%I2clr},%B3 %2,%r1,%0\;ldi 1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (match_operator:DI 3 "comparison_operator"
+ [(match_operand:DI 1 "reg_or_0_operand" "rM")
+ (match_operand:DI 2 "arith11_operand" "rI")]))]
+ "TARGET_64BIT"
+ "cmp%I2clr,*%B3 %2,%r1,%0\;ldi 1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn "iorscc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ior:SI (match_operator:SI 3 "comparison_operator"
+ [(match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "arith11_operand" "rI")])
+ (match_operator:SI 6 "comparison_operator"
+ [(match_operand:SI 4 "reg_or_0_operand" "rM")
+ (match_operand:SI 5 "arith11_operand" "rI")])))]
+ ""
+ "{com%I2clr|cmp%I2clr},%S3 %2,%r1,%%r0\;{com%I5clr|cmp%I5clr},%B6 %5,%r4,%0\;ldi 1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ior:DI (match_operator:DI 3 "comparison_operator"
+ [(match_operand:DI 1 "reg_or_0_operand" "rM")
+ (match_operand:DI 2 "arith11_operand" "rI")])
+ (match_operator:DI 6 "comparison_operator"
+ [(match_operand:DI 4 "reg_or_0_operand" "rM")
+ (match_operand:DI 5 "arith11_operand" "rI")])))]
+ "TARGET_64BIT"
+ "cmp%I2clr,*%S3 %2,%r1,%%r0\;cmp%I5clr,*%B6 %5,%r4,%0\;ldi 1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "12")])
+
+;; Combiner patterns for common operations performed with the output
+;; from an scc insn (negscc and incscc).
+(define_insn "negscc"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (match_operator:SI 3 "comparison_operator"
+ [(match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "arith11_operand" "rI")])))]
+ ""
+ "{com%I2clr|cmp%I2clr},%B3 %2,%r1,%0\;ldi -1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (neg:DI (match_operator:DI 3 "comparison_operator"
+ [(match_operand:DI 1 "reg_or_0_operand" "rM")
+ (match_operand:DI 2 "arith11_operand" "rI")])))]
+ "TARGET_64BIT"
+ "cmp%I2clr,*%B3 %2,%r1,%0\;ldi -1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+;; Patterns for adding/subtracting the result of a boolean expression from
+;; a register. First we have special patterns that make use of the carry
+;; bit, and output only two instructions. For the cases we can't in
+;; general do in two instructions, the incscc pattern at the end outputs
+;; two or three instructions.
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (leu:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "arith11_operand" "rI"))
+ (match_operand:SI 1 "register_operand" "r")))]
+ ""
+ "sub%I3 %3,%2,%%r0\;{addc|add,c} %%r0,%1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (leu:DI (match_operand:DI 2 "register_operand" "r")
+ (match_operand:DI 3 "arith11_operand" "rI"))
+ (match_operand:DI 1 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "sub%I3 %3,%2,%%r0\;add,dc %%r0,%1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+; This need only accept registers for op3, since canonicalization
+; replaces geu with gtu when op3 is an integer.
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (geu:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r"))
+ (match_operand:SI 1 "register_operand" "r")))]
+ ""
+ "sub %2,%3,%%r0\;{addc|add,c} %%r0,%1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (geu:DI (match_operand:DI 2 "register_operand" "r")
+ (match_operand:DI 3 "register_operand" "r"))
+ (match_operand:DI 1 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "sub %2,%3,%%r0\;add,dc %%r0,%1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+; Match only integers for op3 here. This is used as canonical form of the
+; geu pattern when op3 is an integer. Don't match registers since we can't
+; make better code than the general incscc pattern.
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (gtu:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "int11_operand" "I"))
+ (match_operand:SI 1 "register_operand" "r")))]
+ ""
+ "addi %k3,%2,%%r0\;{addc|add,c} %%r0,%1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (gtu:DI (match_operand:DI 2 "register_operand" "r")
+ (match_operand:DI 3 "int11_operand" "I"))
+ (match_operand:DI 1 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "addi %k3,%2,%%r0\;add,dc %%r0,%1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn "incscc"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (plus:SI (match_operator:SI 4 "comparison_operator"
+ [(match_operand:SI 2 "register_operand" "r,r")
+ (match_operand:SI 3 "arith11_operand" "rI,rI")])
+ (match_operand:SI 1 "register_operand" "0,?r")))]
+ ""
+ "@
+ {com%I3clr|cmp%I3clr},%B4 %3,%2,%%r0\;addi 1,%0,%0
+ {com%I3clr|cmp%I3clr},%B4 %3,%2,%%r0\;addi,tr 1,%1,%0\;copy %1,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "length" "8,12")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (plus:DI (match_operator:DI 4 "comparison_operator"
+ [(match_operand:DI 2 "register_operand" "r,r")
+ (match_operand:DI 3 "arith11_operand" "rI,rI")])
+ (match_operand:DI 1 "register_operand" "0,?r")))]
+ "TARGET_64BIT"
+ "@
+ cmp%I3clr,*%B4 %3,%2,%%r0\;addi 1,%0,%0
+ cmp%I3clr,*%B4 %3,%2,%%r0\;addi,tr 1,%1,%0\;copy %1,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "length" "8,12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (gtu:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "arith11_operand" "rI"))))]
+ ""
+ "sub%I3 %3,%2,%%r0\;{subb|sub,b} %1,%%r0,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (gtu:DI (match_operand:DI 2 "register_operand" "r")
+ (match_operand:DI 3 "arith11_operand" "rI"))))]
+ "TARGET_64BIT"
+ "sub%I3 %3,%2,%%r0\;sub,db %1,%%r0,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (gtu:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "arith11_operand" "rI")))
+ (match_operand:SI 4 "register_operand" "r")))]
+ ""
+ "sub%I3 %3,%2,%%r0\;{subb|sub,b} %1,%4,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (gtu:DI (match_operand:DI 2 "register_operand" "r")
+ (match_operand:DI 3 "arith11_operand" "rI")))
+ (match_operand:DI 4 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "sub%I3 %3,%2,%%r0\;sub,db %1,%4,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+; This need only accept registers for op3, since canonicalization
+; replaces ltu with leu when op3 is an integer.
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (ltu:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r"))))]
+ ""
+ "sub %2,%3,%%r0\;{subb|sub,b} %1,%%r0,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (ltu:DI (match_operand:DI 2 "register_operand" "r")
+ (match_operand:DI 3 "register_operand" "r"))))]
+ "TARGET_64BIT"
+ "sub %2,%3,%%r0\;sub,db %1,%%r0,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (ltu:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")))
+ (match_operand:SI 4 "register_operand" "r")))]
+ ""
+ "sub %2,%3,%%r0\;{subb|sub,b} %1,%4,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (ltu:DI (match_operand:DI 2 "register_operand" "r")
+ (match_operand:DI 3 "register_operand" "r")))
+ (match_operand:DI 4 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "sub %2,%3,%%r0\;sub,db %1,%4,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+; Match only integers for op3 here. This is used as canonical form of the
+; ltu pattern when op3 is an integer. Don't match registers since we can't
+; make better code than the general incscc pattern.
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (leu:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "int11_operand" "I"))))]
+ ""
+ "addi %k3,%2,%%r0\;{subb|sub,b} %1,%%r0,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (leu:DI (match_operand:DI 2 "register_operand" "r")
+ (match_operand:DI 3 "int11_operand" "I"))))]
+ "TARGET_64BIT"
+ "addi %k3,%2,%%r0\;sub,db %1,%%r0,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (leu:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "int11_operand" "I")))
+ (match_operand:SI 4 "register_operand" "r")))]
+ ""
+ "addi %k3,%2,%%r0\;{subb|sub,b} %1,%4,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (leu:DI (match_operand:DI 2 "register_operand" "r")
+ (match_operand:DI 3 "int11_operand" "I")))
+ (match_operand:DI 4 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "addi %k3,%2,%%r0\;sub,db %1,%4,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn "decscc"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0,?r")
+ (match_operator:SI 4 "comparison_operator"
+ [(match_operand:SI 2 "register_operand" "r,r")
+ (match_operand:SI 3 "arith11_operand" "rI,rI")])))]
+ ""
+ "@
+ {com%I3clr|cmp%I3clr},%B4 %3,%2,%%r0\;addi -1,%0,%0
+ {com%I3clr|cmp%I3clr},%B4 %3,%2,%%r0\;addi,tr -1,%1,%0\;copy %1,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "length" "8,12")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (minus:DI (match_operand:DI 1 "register_operand" "0,?r")
+ (match_operator:DI 4 "comparison_operator"
+ [(match_operand:DI 2 "register_operand" "r,r")
+ (match_operand:DI 3 "arith11_operand" "rI,rI")])))]
+ "TARGET_64BIT"
+ "@
+ cmp%I3clr,*%B4 %3,%2,%%r0\;addi -1,%0,%0
+ cmp%I3clr,*%B4 %3,%2,%%r0\;addi,tr -1,%1,%0\;copy %1,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "length" "8,12")])
+
+; Patterns for max and min. (There is no need for an earlyclobber in the
+; last alternative since the middle alternative will match if op0 == op1.)
+
+(define_insn "sminsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (smin:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "arith11_operand" "r,I,M")))]
+ ""
+ "@
+ {comclr|cmpclr},> %2,%0,%%r0\;copy %2,%0
+ {comiclr|cmpiclr},> %2,%0,%%r0\;ldi %2,%0
+ {comclr|cmpclr},> %1,%r2,%0\;copy %1,%0"
+[(set_attr "type" "multi,multi,multi")
+ (set_attr "length" "8,8,8")])
+
+(define_insn "smindi3"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,r")
+ (smin:DI (match_operand:DI 1 "register_operand" "%0,0,r")
+ (match_operand:DI 2 "arith11_operand" "r,I,M")))]
+ "TARGET_64BIT"
+ "@
+ cmpclr,*> %2,%0,%%r0\;copy %2,%0
+ cmpiclr,*> %2,%0,%%r0\;ldi %2,%0
+ cmpclr,*> %1,%r2,%0\;copy %1,%0"
+[(set_attr "type" "multi,multi,multi")
+ (set_attr "length" "8,8,8")])
+
+(define_insn "uminsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (umin:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (match_operand:SI 2 "arith11_operand" "r,I")))]
+ ""
+ "@
+ {comclr|cmpclr},>> %2,%0,%%r0\;copy %2,%0
+ {comiclr|cmpiclr},>> %2,%0,%%r0\;ldi %2,%0"
+[(set_attr "type" "multi,multi")
+ (set_attr "length" "8,8")])
+
+(define_insn "umindi3"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (umin:DI (match_operand:DI 1 "register_operand" "%0,0")
+ (match_operand:DI 2 "arith11_operand" "r,I")))]
+ "TARGET_64BIT"
+ "@
+ cmpclr,*>> %2,%0,%%r0\;copy %2,%0
+ cmpiclr,*>> %2,%0,%%r0\;ldi %2,%0"
+[(set_attr "type" "multi,multi")
+ (set_attr "length" "8,8")])
+
+(define_insn "smaxsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (smax:SI (match_operand:SI 1 "register_operand" "%0,0,r")
+ (match_operand:SI 2 "arith11_operand" "r,I,M")))]
+ ""
+ "@
+ {comclr|cmpclr},< %2,%0,%%r0\;copy %2,%0
+ {comiclr|cmpiclr},< %2,%0,%%r0\;ldi %2,%0
+ {comclr|cmpclr},< %1,%r2,%0\;copy %1,%0"
+[(set_attr "type" "multi,multi,multi")
+ (set_attr "length" "8,8,8")])
+
+(define_insn "smaxdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,r")
+ (smax:DI (match_operand:DI 1 "register_operand" "%0,0,r")
+ (match_operand:DI 2 "arith11_operand" "r,I,M")))]
+ "TARGET_64BIT"
+ "@
+ cmpclr,*< %2,%0,%%r0\;copy %2,%0
+ cmpiclr,*< %2,%0,%%r0\;ldi %2,%0
+ cmpclr,*< %1,%r2,%0\;copy %1,%0"
+[(set_attr "type" "multi,multi,multi")
+ (set_attr "length" "8,8,8")])
+
+(define_insn "umaxsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (umax:SI (match_operand:SI 1 "register_operand" "%0,0")
+ (match_operand:SI 2 "arith11_operand" "r,I")))]
+ ""
+ "@
+ {comclr|cmpclr},<< %2,%0,%%r0\;copy %2,%0
+ {comiclr|cmpiclr},<< %2,%0,%%r0\;ldi %2,%0"
+[(set_attr "type" "multi,multi")
+ (set_attr "length" "8,8")])
+
+(define_insn "umaxdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (umax:DI (match_operand:DI 1 "register_operand" "%0,0")
+ (match_operand:DI 2 "arith11_operand" "r,I")))]
+ "TARGET_64BIT"
+ "@
+ cmpclr,*<< %2,%0,%%r0\;copy %2,%0
+ cmpiclr,*<< %2,%0,%%r0\;ldi %2,%0"
+[(set_attr "type" "multi,multi")
+ (set_attr "length" "8,8")])
+
+(define_insn "abssi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (abs:SI (match_operand:SI 1 "register_operand" "r")))]
+ ""
+ "or,>= %%r0,%1,%0\;subi 0,%0,%0"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+(define_insn "absdi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (abs:DI (match_operand:DI 1 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "or,*>= %%r0,%1,%0\;subi 0,%0,%0"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+;;; Experimental conditional move patterns
+
+(define_expand "movsicc"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (if_then_else:SI
+ (match_operand 1 "comparison_operator" "")
+ (match_operand:SI 2 "reg_or_cint_move_operand" "")
+ (match_operand:SI 3 "reg_or_cint_move_operand" "")))]
+ ""
+ "
+{
+ if (GET_MODE (XEXP (operands[1], 0)) != SImode
+ || GET_MODE (XEXP (operands[1], 0)) != GET_MODE (XEXP (operands[1], 1)))
+ FAIL;
+}")
+
+;; We used to accept any register for op1.
+;;
+;; However, it loses sometimes because the compiler will end up using
+;; different registers for op0 and op1 in some critical cases. local-alloc
+;; will not tie op0 and op1 because op0 is used in multiple basic blocks.
+;;
+;; If/when global register allocation supports tying we should allow any
+;; register for op1 again.
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (if_then_else:SI
+ (match_operator 2 "comparison_operator"
+ [(match_operand:SI 3 "register_operand" "r,r,r,r")
+ (match_operand:SI 4 "arith11_operand" "rI,rI,rI,rI")])
+ (match_operand:SI 1 "reg_or_cint_move_operand" "0,J,N,K")
+ (const_int 0)))]
+ ""
+ "@
+ {com%I4clr|cmp%I4clr},%S2 %4,%3,%%r0\;ldi 0,%0
+ {com%I4clr|cmp%I4clr},%B2 %4,%3,%0\;ldi %1,%0
+ {com%I4clr|cmp%I4clr},%B2 %4,%3,%0\;ldil L'%1,%0
+ {com%I4clr|cmp%I4clr},%B2 %4,%3,%0\;{zdepi|depwi,z} %Z1,%0"
+ [(set_attr "type" "multi,multi,multi,nullshift")
+ (set_attr "length" "8,8,8,8")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r")
+ (if_then_else:SI
+ (match_operator 5 "comparison_operator"
+ [(match_operand:SI 3 "register_operand" "r,r,r,r,r,r,r,r")
+ (match_operand:SI 4 "arith11_operand" "rI,rI,rI,rI,rI,rI,rI,rI")])
+ (match_operand:SI 1 "reg_or_cint_move_operand" "0,0,0,0,r,J,N,K")
+ (match_operand:SI 2 "reg_or_cint_move_operand" "r,J,N,K,0,0,0,0")))]
+ ""
+ "@
+ {com%I4clr|cmp%I4clr},%S5 %4,%3,%%r0\;copy %2,%0
+ {com%I4clr|cmp%I4clr},%S5 %4,%3,%%r0\;ldi %2,%0
+ {com%I4clr|cmp%I4clr},%S5 %4,%3,%%r0\;ldil L'%2,%0
+ {com%I4clr|cmp%I4clr},%S5 %4,%3,%%r0\;{zdepi|depwi,z} %Z2,%0
+ {com%I4clr|cmp%I4clr},%B5 %4,%3,%%r0\;copy %1,%0
+ {com%I4clr|cmp%I4clr},%B5 %4,%3,%%r0\;ldi %1,%0
+ {com%I4clr|cmp%I4clr},%B5 %4,%3,%%r0\;ldil L'%1,%0
+ {com%I4clr|cmp%I4clr},%B5 %4,%3,%%r0\;{zdepi|depwi,z} %Z1,%0"
+ [(set_attr "type" "multi,multi,multi,nullshift,multi,multi,multi,nullshift")
+ (set_attr "length" "8,8,8,8,8,8,8,8")])
+
+(define_expand "movdicc"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (if_then_else:DI
+ (match_operand 1 "comparison_operator" "")
+ (match_operand:DI 2 "reg_or_cint_move_operand" "")
+ (match_operand:DI 3 "reg_or_cint_move_operand" "")))]
+ "TARGET_64BIT"
+ "
+{
+ if (GET_MODE (XEXP (operands[1], 0)) != DImode
+ || GET_MODE (XEXP (operands[1], 0)) != GET_MODE (XEXP (operands[1], 1)))
+ FAIL;
+}")
+
+; We need the first constraint alternative in order to avoid
+; earlyclobbers on all other alternatives.
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r")
+ (if_then_else:DI
+ (match_operator 2 "comparison_operator"
+ [(match_operand:DI 3 "register_operand" "r,r,r,r,r")
+ (match_operand:DI 4 "arith11_operand" "rI,rI,rI,rI,rI")])
+ (match_operand:DI 1 "reg_or_cint_move_operand" "0,r,J,N,K")
+ (const_int 0)))]
+ "TARGET_64BIT"
+ "@
+ cmp%I4clr,*%S2 %4,%3,%%r0\;ldi 0,%0
+ cmp%I4clr,*%B2 %4,%3,%0\;copy %1,%0
+ cmp%I4clr,*%B2 %4,%3,%0\;ldi %1,%0
+ cmp%I4clr,*%B2 %4,%3,%0\;ldil L'%1,%0
+ cmp%I4clr,*%B2 %4,%3,%0\;depdi,z %z1,%0"
+ [(set_attr "type" "multi,multi,multi,multi,nullshift")
+ (set_attr "length" "8,8,8,8,8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r,r,r")
+ (if_then_else:DI
+ (match_operator 5 "comparison_operator"
+ [(match_operand:DI 3 "register_operand" "r,r,r,r,r,r,r,r")
+ (match_operand:DI 4 "arith11_operand" "rI,rI,rI,rI,rI,rI,rI,rI")])
+ (match_operand:DI 1 "reg_or_cint_move_operand" "0,0,0,0,r,J,N,K")
+ (match_operand:DI 2 "reg_or_cint_move_operand" "r,J,N,K,0,0,0,0")))]
+ "TARGET_64BIT"
+ "@
+ cmp%I4clr,*%S5 %4,%3,%%r0\;copy %2,%0
+ cmp%I4clr,*%S5 %4,%3,%%r0\;ldi %2,%0
+ cmp%I4clr,*%S5 %4,%3,%%r0\;ldil L'%2,%0
+ cmp%I4clr,*%S5 %4,%3,%%r0\;depdi,z %z2,%0
+ cmp%I4clr,*%B5 %4,%3,%%r0\;copy %1,%0
+ cmp%I4clr,*%B5 %4,%3,%%r0\;ldi %1,%0
+ cmp%I4clr,*%B5 %4,%3,%%r0\;ldil L'%1,%0
+ cmp%I4clr,*%B5 %4,%3,%%r0\;depdi,z %z1,%0"
+ [(set_attr "type" "multi,multi,multi,nullshift,multi,multi,multi,nullshift")
+ (set_attr "length" "8,8,8,8,8,8,8,8")])
+
+;; Conditional Branches
+
+(define_expand "cbranchdi4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:DI 1 "reg_or_0_operand" "")
+ (match_operand:DI 2 "register_operand" "")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ "TARGET_64BIT"
+ "")
+
+(define_expand "cbranchsi4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:SI 1 "reg_or_0_operand" "")
+ (match_operand:SI 2 "arith5_operand" "")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_expand "cbranchsf4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(match_operand:SF 1 "reg_or_0_operand" "")
+ (match_operand:SF 2 "reg_or_0_operand" "")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ pa_emit_bcond_fp (operands);
+ DONE;
+}")
+
+
+(define_expand "cbranchdf4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(match_operand:DF 1 "reg_or_0_operand" "")
+ (match_operand:DF 2 "reg_or_0_operand" "")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ pa_emit_bcond_fp (operands);
+ DONE;
+}")
+
+;; Match the branch patterns.
+
+
+;; Note a long backward conditional branch with an annulled delay slot
+;; has a length of 12.
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (match_operator 3 "comparison_operator"
+ [(match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "arith5_operand" "rL")])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "*
+{
+ return pa_output_cbranch (operands, 0, insn);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+;; Match the negated branch.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (match_operator 3 "comparison_operator"
+ [(match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "arith5_operand" "rL")])
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "*
+{
+ return pa_output_cbranch (operands, 1, insn);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (match_operator 3 "comparison_operator"
+ [(match_operand:DI 1 "reg_or_0_operand" "rM")
+ (match_operand:DI 2 "reg_or_0_operand" "rM")])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_cbranch (operands, 0, insn);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+;; Match the negated branch.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (match_operator 3 "comparison_operator"
+ [(match_operand:DI 1 "reg_or_0_operand" "rM")
+ (match_operand:DI 2 "reg_or_0_operand" "rM")])
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_cbranch (operands, 1, insn);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (match_operator 3 "cmpib_comparison_operator"
+ [(match_operand:DI 1 "reg_or_0_operand" "rM")
+ (match_operand:DI 2 "arith5_operand" "rL")])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_cbranch (operands, 0, insn);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+;; Match the negated branch.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (match_operator 3 "cmpib_comparison_operator"
+ [(match_operand:DI 1 "reg_or_0_operand" "rM")
+ (match_operand:DI 2 "arith5_operand" "rL")])
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_cbranch (operands, 1, insn);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+;; Branch on Bit patterns.
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 1 "uint5_operand" ""))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ ""
+ "*
+{
+ return pa_output_bb (operands, 0, insn, 0);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (zero_extract:DI (match_operand:DI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:DI 1 "uint32_operand" ""))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_bb (operands, 0, insn, 0);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 1 "uint5_operand" ""))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ ""
+ "*
+{
+ return pa_output_bb (operands, 1, insn, 0);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (zero_extract:DI (match_operand:DI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:DI 1 "uint32_operand" ""))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_bb (operands, 1, insn, 0);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 1 "uint5_operand" ""))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ ""
+ "*
+{
+ return pa_output_bb (operands, 0, insn, 1);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (zero_extract:DI (match_operand:DI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:DI 1 "uint32_operand" ""))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_bb (operands, 0, insn, 1);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 1 "uint5_operand" ""))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ ""
+ "*
+{
+ return pa_output_bb (operands, 1, insn, 1);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (zero_extract:DI (match_operand:DI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:DI 1 "uint32_operand" ""))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_bb (operands, 1, insn, 1);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+;; Branch on Variable Bit patterns.
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 1 "register_operand" "q"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ ""
+ "*
+{
+ return pa_output_bvb (operands, 0, insn, 0);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (zero_extract:DI (match_operand:DI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:DI 1 "register_operand" "q"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_bvb (operands, 0, insn, 0);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 1 "register_operand" "q"))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ ""
+ "*
+{
+ return pa_output_bvb (operands, 1, insn, 0);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (zero_extract:DI (match_operand:DI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:DI 1 "register_operand" "q"))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_bvb (operands, 1, insn, 0);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 1 "register_operand" "q"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ ""
+ "*
+{
+ return pa_output_bvb (operands, 0, insn, 1);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (zero_extract:DI (match_operand:DI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:DI 1 "register_operand" "q"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_bvb (operands, 0, insn, 1);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 1 "register_operand" "q"))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ ""
+ "*
+{
+ return pa_output_bvb (operands, 1, insn, 1);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (zero_extract:DI (match_operand:DI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:DI 1 "register_operand" "q"))
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_bvb (operands, 1, insn, 1);
+}"
+[(set_attr "type" "cbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+;; Floating point branches
+
+;; ??? Nullification is handled differently from other branches.
+;; If nullification is specified, the delay slot is nullified on any
+;; taken branch regardless of branch direction.
+(define_insn ""
+ [(set (pc) (if_then_else (ne (reg:CCFP 0) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ "!TARGET_SOFT_FLOAT"
+ "*
+{
+ int length = get_attr_length (insn);
+ rtx xoperands[1];
+ int nullify, xdelay;
+
+ if (length < 16)
+ return \"ftest\;b%* %l0\";
+
+ if (dbr_sequence_length () == 0 || INSN_ANNULLED_BRANCH_P (insn))
+ {
+ nullify = 1;
+ xdelay = 0;
+ xoperands[0] = GEN_INT (length - 8);
+ }
+ else
+ {
+ nullify = 0;
+ xdelay = 1;
+ xoperands[0] = GEN_INT (length - 4);
+ }
+
+ if (nullify)
+ output_asm_insn (\"ftest\;add,tr %%r0,%%r0,%%r0\;b,n .+%0\", xoperands);
+ else
+ output_asm_insn (\"ftest\;add,tr %%r0,%%r0,%%r0\;b .+%0\", xoperands);
+ return pa_output_lbranch (operands[0], insn, xdelay);
+}"
+[(set_attr "type" "fbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 32)
+ (not (match_test "flag_pic"))
+ (const_int 28)]
+ (const_int 36)))])
+
+(define_insn ""
+ [(set (pc) (if_then_else (ne (reg:CCFP 0) (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ "!TARGET_SOFT_FLOAT"
+ "*
+{
+ int length = get_attr_length (insn);
+ rtx xoperands[1];
+ int nullify, xdelay;
+
+ if (length < 16)
+ return \"ftest\;add,tr %%r0,%%r0,%%r0\;b%* %0\";
+
+ if (dbr_sequence_length () == 0 || INSN_ANNULLED_BRANCH_P (insn))
+ {
+ nullify = 1;
+ xdelay = 0;
+ xoperands[0] = GEN_INT (length - 4);
+ }
+ else
+ {
+ nullify = 0;
+ xdelay = 1;
+ xoperands[0] = GEN_INT (length);
+ }
+
+ if (nullify)
+ output_asm_insn (\"ftest\;b,n .+%0\", xoperands);
+ else
+ output_asm_insn (\"ftest\;b .+%0\", xoperands);
+ return pa_output_lbranch (operands[0], insn, xdelay);
+}"
+[(set_attr "type" "fbranch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 12)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 28)
+ (not (match_test "flag_pic"))
+ (const_int 24)]
+ (const_int 32)))])
+
+;; Move instructions
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "general_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, SImode, 0))
+ DONE;
+}")
+
+;; Handle SImode input reloads requiring %r1 as a scratch register.
+(define_expand "reload_insi_r1"
+ [(set (match_operand:SI 0 "register_operand" "=Z")
+ (match_operand:SI 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=&a"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, SImode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle SImode input reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_insi"
+ [(set (match_operand:SI 0 "register_operand" "=Z")
+ (match_operand:SI 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, SImode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle SImode output reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_outsi"
+ [(set (match_operand:SI 0 "non_hard_reg_operand" "")
+ (match_operand:SI 1 "register_operand" "Z"))
+ (clobber (match_operand:SI 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, SImode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "move_dest_operand"
+ "=r,r,r,r,r,r,Q,!*q,!r,!*f,*f,T,?r,?*f")
+ (match_operand:SI 1 "move_src_operand"
+ "A,r,J,N,K,RQ,rM,!rM,!*q,!*fM,RT,*f,*f,r"))]
+ "(register_operand (operands[0], SImode)
+ || reg_or_0_operand (operands[1], SImode))
+ && !TARGET_SOFT_FLOAT
+ && !TARGET_64BIT"
+ "@
+ ldw RT'%A1,%0
+ copy %1,%0
+ ldi %1,%0
+ ldil L'%1,%0
+ {zdepi|depwi,z} %Z1,%0
+ ldw%M1 %1,%0
+ stw%M0 %r1,%0
+ mtsar %r1
+ {mfctl|mfctl,w} %%sar,%0
+ fcpy,sgl %f1,%0
+ fldw%F1 %1,%0
+ fstw%F0 %1,%0
+ {fstws|fstw} %1,-16(%%sp)\n\t{ldws|ldw} -16(%%sp),%0
+ {stws|stw} %1,-16(%%sp)\n\t{fldws|fldw} -16(%%sp),%0"
+ [(set_attr "type" "load,move,move,move,shift,load,store,move,move,fpalu,fpload,fpstore,fpstore_load,store_fpload")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4,8,8")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "move_dest_operand"
+ "=r,r,r,r,r,r,Q,!*q,!r,!*f,*f,T")
+ (match_operand:SI 1 "move_src_operand"
+ "A,r,J,N,K,RQ,rM,!rM,!*q,!*fM,RT,*f"))]
+ "(register_operand (operands[0], SImode)
+ || reg_or_0_operand (operands[1], SImode))
+ && !TARGET_SOFT_FLOAT
+ && TARGET_64BIT"
+ "@
+ ldw RT'%A1,%0
+ copy %1,%0
+ ldi %1,%0
+ ldil L'%1,%0
+ {zdepi|depwi,z} %Z1,%0
+ ldw%M1 %1,%0
+ stw%M0 %r1,%0
+ mtsar %r1
+ {mfctl|mfctl,w} %%sar,%0
+ fcpy,sgl %f1,%0
+ fldw%F1 %1,%0
+ fstw%F0 %1,%0"
+ [(set_attr "type" "load,move,move,move,shift,load,store,move,move,fpalu,fpload,fpstore")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "indexed_memory_operand" "=R")
+ (match_operand:SI 1 "register_operand" "f"))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && reload_completed"
+ "fstw%F0 %1,%0"
+ [(set_attr "type" "fpstore")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4")])
+
+; Rewrite RTL using an indexed store. This will allow the insn that
+; computes the address to be deleted if the register it sets is dead.
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 4))
+ (match_operand:SI 2 "register_operand" "")))
+ (set (mem:SI (match_dup 0))
+ (match_operand:SI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SI (plus:SI (mult:SI (match_dup 1) (const_int 4)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (mult:SI (match_dup 1) (const_int 4))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 2 "register_operand" "")
+ (mult:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 4))))
+ (set (mem:SI (match_dup 0))
+ (match_operand:SI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SI (plus:SI (mult:SI (match_dup 1) (const_int 4)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (mult:SI (match_dup 1) (const_int 4))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (mult:DI (match_operand:DI 1 "register_operand" "")
+ (const_int 4))
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:SI (match_dup 0))
+ (match_operand:SI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SI (plus:DI (mult:DI (match_dup 1) (const_int 4)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (mult:DI (match_dup 1) (const_int 4))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 2 "register_operand" "")
+ (mult:DI (match_operand:DI 1 "register_operand" "")
+ (const_int 4))))
+ (set (mem:SI (match_dup 0))
+ (match_operand:SI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SI (plus:DI (mult:DI (match_dup 1) (const_int 4)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (mult:DI (match_dup 1) (const_int 4))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (mem:SI (match_dup 0))
+ (match_operand:SI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_INDEX_P (operands[1])
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SI (plus:SI (match_dup 1) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (mem:SI (match_dup 0))
+ (match_operand:SI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_BASE_P (operands[1])
+ && REG_OK_FOR_INDEX_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SI (plus:SI (match_dup 2) (match_dup 1)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (match_dup 2) (match_dup 1)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:SI (match_dup 0))
+ (match_operand:SI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_INDEX_P (operands[1])
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SI (plus:DI (match_dup 1) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:SI (match_dup 0))
+ (match_operand:SI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_BASE_P (operands[1])
+ && REG_OK_FOR_INDEX_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SI (plus:DI (match_dup 2) (match_dup 1)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (match_dup 2) (match_dup 1)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "move_dest_operand"
+ "=r,r,r,r,r,r,Q,!*q,!r")
+ (match_operand:SI 1 "move_src_operand"
+ "A,r,J,N,K,RQ,rM,!rM,!*q"))]
+ "(register_operand (operands[0], SImode)
+ || reg_or_0_operand (operands[1], SImode))
+ && TARGET_SOFT_FLOAT"
+ "@
+ ldw RT'%A1,%0
+ copy %1,%0
+ ldi %1,%0
+ ldil L'%1,%0
+ {zdepi|depwi,z} %Z1,%0
+ ldw%M1 %1,%0
+ stw%M0 %r1,%0
+ mtsar %r1
+ {mfctl|mfctl,w} %%sar,%0"
+ [(set_attr "type" "load,move,move,move,move,load,store,move,move")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4,4,4,4,4,4,4,4")])
+
+;; Load or store with base-register modification.
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mem:SI (plus:DI (match_operand:DI 1 "register_operand" "+r")
+ (match_operand:DI 2 "int5_operand" "L"))))
+ (set (match_dup 1)
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_64BIT"
+ "ldw,mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+; And a zero extended variant.
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI (mem:SI
+ (plus:DI
+ (match_operand:DI 1 "register_operand" "+r")
+ (match_operand:DI 2 "int5_operand" "L")))))
+ (set (match_dup 1)
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_64BIT"
+ "ldw,mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_expand "pre_load"
+ [(parallel [(set (match_operand:SI 0 "register_operand" "")
+ (mem (plus (match_operand 1 "register_operand" "")
+ (match_operand 2 "pre_cint_operand" ""))))
+ (set (match_dup 1)
+ (plus (match_dup 1) (match_dup 2)))])]
+ ""
+ "
+{
+ if (TARGET_64BIT)
+ {
+ emit_insn (gen_pre_ldd (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ emit_insn (gen_pre_ldw (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "pre_ldw"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "+r")
+ (match_operand:SI 2 "pre_cint_operand" ""))))
+ (set (match_dup 1)
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "*
+{
+ if (INTVAL (operands[2]) < 0)
+ return \"{ldwm|ldw,mb} %2(%1),%0\";
+ return \"{ldws|ldw},mb %2(%1),%0\";
+}"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn "pre_ldd"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mem:DI (plus:DI (match_operand:DI 1 "register_operand" "+r")
+ (match_operand:DI 2 "pre_cint_operand" ""))))
+ (set (match_dup 1)
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_64BIT"
+ "ldd,mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "+r")
+ (match_operand:SI 1 "pre_cint_operand" "")))
+ (match_operand:SI 2 "reg_or_0_operand" "rM"))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0) (match_dup 1)))]
+ ""
+ "*
+{
+ if (INTVAL (operands[1]) < 0)
+ return \"{stwm|stw,mb} %r2,%1(%0)\";
+ return \"{stws|stw},mb %r2,%1(%0)\";
+}"
+ [(set_attr "type" "store")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mem:SI (match_operand:SI 1 "register_operand" "+r")))
+ (set (match_dup 1)
+ (plus:SI (match_dup 1)
+ (match_operand:SI 2 "post_cint_operand" "")))]
+ ""
+ "*
+{
+ if (INTVAL (operands[2]) > 0)
+ return \"{ldwm|ldw,ma} %2(%1),%0\";
+ return \"{ldws|ldw},ma %2(%1),%0\";
+}"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_expand "post_store"
+ [(parallel [(set (mem (match_operand 0 "register_operand" ""))
+ (match_operand 1 "reg_or_0_operand" ""))
+ (set (match_dup 0)
+ (plus (match_dup 0)
+ (match_operand 2 "post_cint_operand" "")))])]
+ ""
+ "
+{
+ if (TARGET_64BIT)
+ {
+ emit_insn (gen_post_std (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ emit_insn (gen_post_stw (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "post_stw"
+ [(set (mem:SI (match_operand:SI 0 "register_operand" "+r"))
+ (match_operand:SI 1 "reg_or_0_operand" "rM"))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (match_operand:SI 2 "post_cint_operand" "")))]
+ ""
+ "*
+{
+ if (INTVAL (operands[2]) > 0)
+ return \"{stwm|stw,ma} %r1,%2(%0)\";
+ return \"{stws|stw},ma %r1,%2(%0)\";
+}"
+ [(set_attr "type" "store")
+ (set_attr "length" "4")])
+
+(define_insn "post_std"
+ [(set (mem:DI (match_operand:DI 0 "register_operand" "+r"))
+ (match_operand:DI 1 "reg_or_0_operand" "rM"))
+ (set (match_dup 0)
+ (plus:DI (match_dup 0)
+ (match_operand:DI 2 "post_cint_operand" "")))]
+ "TARGET_64BIT"
+ "std,ma %r1,%2(%0)"
+ [(set_attr "type" "store")
+ (set_attr "length" "4")])
+
+;; For loading the address of a label while generating PIC code.
+;; Note since this pattern can be created at reload time (via movsi), all
+;; the same rules for movsi apply here. (no new pseudos, no temporaries).
+(define_insn ""
+ [(set (match_operand 0 "pmode_register_operand" "=a")
+ (match_operand 1 "pic_label_operand" ""))]
+ "TARGET_PA_20"
+ "*
+{
+ rtx xoperands[3];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = operands[1];
+ xoperands[2] = gen_label_rtx ();
+
+ (*targetm.asm_out.internal_label) (asm_out_file, \"L\",
+ CODE_LABEL_NUMBER (xoperands[2]));
+ output_asm_insn (\"mfia %0\", xoperands);
+
+ /* If we're trying to load the address of a label that happens to be
+ close, then we can use a shorter sequence. */
+ if (GET_CODE (operands[1]) == LABEL_REF
+ && !LABEL_REF_NONLOCAL_P (operands[1])
+ && INSN_ADDRESSES_SET_P ()
+ && abs (INSN_ADDRESSES (INSN_UID (XEXP (operands[1], 0)))
+ - INSN_ADDRESSES (INSN_UID (insn))) < 8100)
+ output_asm_insn (\"ldo %1-%2(%0),%0\", xoperands);
+ else
+ {
+ output_asm_insn (\"addil L%%%1-%2,%0\", xoperands);
+ output_asm_insn (\"ldo R%%%1-%2(%0),%0\", xoperands);
+ }
+ return \"\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "12")]) ; 8 or 12
+
+(define_insn ""
+ [(set (match_operand 0 "pmode_register_operand" "=a")
+ (match_operand 1 "pic_label_operand" ""))]
+ "!TARGET_PA_20"
+ "*
+{
+ rtx xoperands[3];
+
+ xoperands[0] = operands[0];
+ xoperands[1] = operands[1];
+ xoperands[2] = gen_label_rtx ();
+
+ output_asm_insn (\"bl .+8,%0\", xoperands);
+ output_asm_insn (\"depi 0,31,2,%0\", xoperands);
+ (*targetm.asm_out.internal_label) (asm_out_file, \"L\",
+ CODE_LABEL_NUMBER (xoperands[2]));
+
+ /* If we're trying to load the address of a label that happens to be
+ close, then we can use a shorter sequence. */
+ if (GET_CODE (operands[1]) == LABEL_REF
+ && !LABEL_REF_NONLOCAL_P (operands[1])
+ && INSN_ADDRESSES_SET_P ()
+ && abs (INSN_ADDRESSES (INSN_UID (XEXP (operands[1], 0)))
+ - INSN_ADDRESSES (INSN_UID (insn))) < 8100)
+ output_asm_insn (\"ldo %1-%2(%0),%0\", xoperands);
+ else
+ {
+ output_asm_insn (\"addil L%%%1-%2,%0\", xoperands);
+ output_asm_insn (\"ldo R%%%1-%2(%0),%0\", xoperands);
+ }
+ return \"\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "16")]) ; 12 or 16
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (high:SI (match_operand 2 "" ""))))]
+ "symbolic_operand (operands[2], Pmode)
+ && ! function_label_operand (operands[2], Pmode)
+ && flag_pic"
+ "addil LT'%G2,%1"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (plus:DI (match_operand:DI 1 "register_operand" "r")
+ (high:DI (match_operand 2 "" ""))))]
+ "symbolic_operand (operands[2], Pmode)
+ && ! function_label_operand (operands[2], Pmode)
+ && TARGET_64BIT
+ && flag_pic"
+ "addil LT'%G2,%1"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+;; Always use addil rather than ldil;add sequences. This allows the
+;; HP linker to eliminate the dp relocation if the symbolic operand
+;; lives in the TEXT space.
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (high:SI (match_operand 1 "" "")))]
+ "symbolic_operand (operands[1], Pmode)
+ && ! function_label_operand (operands[1], Pmode)
+ && ! read_only_operand (operands[1], Pmode)
+ && ! flag_pic"
+ "*
+{
+ if (TARGET_LONG_LOAD_STORE)
+ return \"addil NLR'%H1,%%r27\;ldo N'%H1(%%r1),%%r1\";
+ else
+ return \"addil LR'%H1,%%r27\";
+}"
+ [(set_attr "type" "binary")
+ (set (attr "length")
+ (if_then_else (not (match_test "TARGET_LONG_LOAD_STORE"))
+ (const_int 4)
+ (const_int 8)))])
+
+
+;; This is for use in the prologue/epilogue code. We need it
+;; to add large constants to a stack pointer or frame pointer.
+;; Because of the additional %r1 pressure, we probably do not
+;; want to use this in general code, so make it available
+;; only after reload.
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=!a,*r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r,r")
+ (high:SI (match_operand 2 "const_int_operand" ""))))]
+ "reload_completed"
+ "@
+ addil L'%G2,%1
+ ldil L'%G2,%0\;{addl|add,l} %0,%1,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "length" "4,8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=!a,*r")
+ (plus:DI (match_operand:DI 1 "register_operand" "r,r")
+ (high:DI (match_operand 2 "const_int_operand" ""))))]
+ "reload_completed && TARGET_64BIT"
+ "@
+ addil L'%G2,%1
+ ldil L'%G2,%0\;{addl|add,l} %0,%1,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "length" "4,8")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (high:SI (match_operand 1 "" "")))]
+ "(!flag_pic || !symbolic_operand (operands[1], Pmode))
+ && !pa_is_function_label_plus_const (operands[1])"
+ "*
+{
+ if (symbolic_operand (operands[1], Pmode))
+ return \"ldil LR'%H1,%0\";
+ else
+ return \"ldil L'%G1,%0\";
+}"
+ [(set_attr "type" "move")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (high:DI (match_operand 1 "const_int_operand" "")))]
+ "TARGET_64BIT"
+ "ldil L'%G1,%0";
+ [(set_attr "type" "move")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lo_sum:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "const_int_operand" "i")))]
+ "TARGET_64BIT"
+ "ldo R'%G2(%1),%0";
+ [(set_attr "type" "move")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "immediate_operand" "i")))]
+ "!pa_is_function_label_plus_const (operands[2])"
+ "*
+{
+ gcc_assert (!flag_pic || !symbolic_operand (operands[2], Pmode));
+
+ if (symbolic_operand (operands[2], Pmode))
+ return \"ldo RR'%G2(%1),%0\";
+ else
+ return \"ldo R'%G2(%1),%0\";
+}"
+ [(set_attr "type" "move")
+ (set_attr "length" "4")])
+
+;; Now that a symbolic_address plus a constant is broken up early
+;; in the compilation phase (for better CSE) we need a special
+;; combiner pattern to load the symbolic address plus the constant
+;; in only 2 instructions. (For cases where the symbolic address
+;; was not a common subexpression.)
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "symbolic_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" ""))]
+ "! (flag_pic && pic_label_operand (operands[1], SImode))"
+ [(set (match_dup 2) (high:SI (match_dup 1)))
+ (set (match_dup 0) (lo_sum:SI (match_dup 2) (match_dup 1)))]
+ "")
+
+;; hppa_legitimize_address goes to a great deal of trouble to
+;; create addresses which use indexing. In some cases, this
+;; is a lose because there isn't any store instructions which
+;; allow indexed addresses (with integer register source).
+;;
+;; These define_splits try to turn a 3 insn store into
+;; a 2 insn store with some creative RTL rewriting.
+(define_split
+ [(set (mem:SI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "shadd_operand" ""))
+ (plus:SI (match_operand:SI 2 "register_operand" "")
+ (match_operand:SI 3 "const_int_operand" ""))))
+ (match_operand:SI 4 "register_operand" ""))
+ (clobber (match_operand:SI 5 "register_operand" ""))]
+ ""
+ [(set (match_dup 5) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
+ (match_dup 2)))
+ (set (mem:SI (plus:SI (match_dup 5) (match_dup 3))) (match_dup 4))]
+ "")
+
+(define_split
+ [(set (mem:HI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "shadd_operand" ""))
+ (plus:SI (match_operand:SI 2 "register_operand" "")
+ (match_operand:SI 3 "const_int_operand" ""))))
+ (match_operand:HI 4 "register_operand" ""))
+ (clobber (match_operand:SI 5 "register_operand" ""))]
+ ""
+ [(set (match_dup 5) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
+ (match_dup 2)))
+ (set (mem:HI (plus:SI (match_dup 5) (match_dup 3))) (match_dup 4))]
+ "")
+
+(define_split
+ [(set (mem:QI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "shadd_operand" ""))
+ (plus:SI (match_operand:SI 2 "register_operand" "")
+ (match_operand:SI 3 "const_int_operand" ""))))
+ (match_operand:QI 4 "register_operand" ""))
+ (clobber (match_operand:SI 5 "register_operand" ""))]
+ ""
+ [(set (match_dup 5) (plus:SI (mult:SI (match_dup 0) (match_dup 1))
+ (match_dup 2)))
+ (set (mem:QI (plus:SI (match_dup 5) (match_dup 3))) (match_dup 4))]
+ "")
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "general_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, HImode, 0))
+ DONE;
+}")
+
+;; Handle HImode input reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_inhi"
+ [(set (match_operand:HI 0 "register_operand" "=Z")
+ (match_operand:HI 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:HI 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, HImode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle HImode output reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_outhi"
+ [(set (match_operand:HI 0 "non_hard_reg_operand" "")
+ (match_operand:HI 1 "register_operand" "Z"))
+ (clobber (match_operand:HI 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, HImode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "move_dest_operand"
+ "=r,r,r,r,r,Q,!*q,!r")
+ (match_operand:HI 1 "move_src_operand"
+ "r,J,N,K,RQ,rM,!rM,!*q"))]
+ "(register_operand (operands[0], HImode)
+ || reg_or_0_operand (operands[1], HImode))"
+ "@
+ copy %1,%0
+ ldi %1,%0
+ ldil L'%1,%0
+ {zdepi|depwi,z} %Z1,%0
+ ldh%M1 %1,%0
+ sth%M0 %r1,%0
+ mtsar %r1
+ {mfctl|mfctl,w} %sar,%0"
+ [(set_attr "type" "move,move,move,shift,load,store,move,move")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4,4,4,4,4,4,4")])
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (mem:HI (plus:SI (match_operand:SI 1 "register_operand" "+r")
+ (match_operand:SI 2 "int5_operand" "L"))))
+ (set (match_dup 1)
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "{ldhs|ldh},mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (mem:HI (plus:DI (match_operand:DI 1 "register_operand" "+r")
+ (match_operand:DI 2 "int5_operand" "L"))))
+ (set (match_dup 1)
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_64BIT"
+ "ldh,mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+; And a zero extended variant.
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI (mem:HI
+ (plus:DI
+ (match_operand:DI 1 "register_operand" "+r")
+ (match_operand:DI 2 "int5_operand" "L")))))
+ (set (match_dup 1)
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_64BIT"
+ "ldh,mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (mem:HI
+ (plus:SI
+ (match_operand:SI 1 "register_operand" "+r")
+ (match_operand:SI 2 "int5_operand" "L")))))
+ (set (match_dup 1)
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "{ldhs|ldh},mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (mem:HI
+ (plus:DI
+ (match_operand:DI 1 "register_operand" "+r")
+ (match_operand:DI 2 "int5_operand" "L")))))
+ (set (match_dup 1)
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_64BIT"
+ "ldh,mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (mem:HI (plus:SI (match_operand:SI 0 "register_operand" "+r")
+ (match_operand:SI 1 "int5_operand" "L")))
+ (match_operand:HI 2 "reg_or_0_operand" "rM"))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0) (match_dup 1)))]
+ ""
+ "{sths|sth},mb %r2,%1(%0)"
+ [(set_attr "type" "store")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (mem:HI (plus:DI (match_operand:DI 0 "register_operand" "+r")
+ (match_operand:DI 1 "int5_operand" "L")))
+ (match_operand:HI 2 "reg_or_0_operand" "rM"))
+ (set (match_dup 0)
+ (plus:DI (match_dup 0) (match_dup 1)))]
+ "TARGET_64BIT"
+ "sth,mb %r2,%1(%0)"
+ [(set_attr "type" "store")
+ (set_attr "length" "4")])
+
+(define_insn "addhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (plus:HI (match_operand:HI 1 "register_operand" "%r,r")
+ (match_operand:HI 2 "arith14_operand" "r,J")))]
+ ""
+ "@
+ {addl|add,l} %1,%2,%0
+ ldo %2(%1),%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4")])
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "general_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, QImode, 0))
+ DONE;
+}")
+
+;; Handle QImode input reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_inqi"
+ [(set (match_operand:QI 0 "register_operand" "=Z")
+ (match_operand:QI 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:QI 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, QImode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle QImode output reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_outqi"
+ [(set (match_operand:QI 0 "non_hard_reg_operand" "")
+ (match_operand:QI 1 "register_operand" "Z"))
+ (clobber (match_operand:QI 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, QImode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn ""
+ [(set (match_operand:QI 0 "move_dest_operand"
+ "=r,r,r,r,r,Q,!*q,!r")
+ (match_operand:QI 1 "move_src_operand"
+ "r,J,N,K,RQ,rM,!rM,!*q"))]
+ "(register_operand (operands[0], QImode)
+ || reg_or_0_operand (operands[1], QImode))"
+ "@
+ copy %1,%0
+ ldi %1,%0
+ ldil L'%1,%0
+ {zdepi|depwi,z} %Z1,%0
+ ldb%M1 %1,%0
+ stb%M0 %r1,%0
+ mtsar %r1
+ {mfctl|mfctl,w} %%sar,%0"
+ [(set_attr "type" "move,move,move,shift,load,store,move,move")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4,4,4,4,4,4,4")])
+
+(define_insn ""
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (mem:QI (plus:SI (match_operand:SI 1 "register_operand" "+r")
+ (match_operand:SI 2 "int5_operand" "L"))))
+ (set (match_dup 1) (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "{ldbs|ldb},mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (mem:QI (plus:DI (match_operand:DI 1 "register_operand" "+r")
+ (match_operand:DI 2 "int5_operand" "L"))))
+ (set (match_dup 1) (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_64BIT"
+ "ldb,mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+; Now the same thing with zero extensions.
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI (mem:QI (plus:DI
+ (match_operand:DI 1 "register_operand" "+r")
+ (match_operand:DI 2 "int5_operand" "L")))))
+ (set (match_dup 1) (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_64BIT"
+ "ldb,mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (mem:QI (plus:SI
+ (match_operand:SI 1 "register_operand" "+r")
+ (match_operand:SI 2 "int5_operand" "L")))))
+ (set (match_dup 1) (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "{ldbs|ldb},mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (mem:QI (plus:DI
+ (match_operand:DI 1 "register_operand" "+r")
+ (match_operand:DI 2 "int5_operand" "L")))))
+ (set (match_dup 1) (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_64BIT"
+ "ldb,mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (zero_extend:HI (mem:QI (plus:SI
+ (match_operand:SI 1 "register_operand" "+r")
+ (match_operand:SI 2 "int5_operand" "L")))))
+ (set (match_dup 1) (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "{ldbs|ldb},mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (zero_extend:HI (mem:QI (plus:DI
+ (match_operand:DI 1 "register_operand" "+r")
+ (match_operand:DI 2 "int5_operand" "L")))))
+ (set (match_dup 1) (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_64BIT"
+ "ldb,mb %2(%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (mem:QI (plus:SI (match_operand:SI 0 "register_operand" "+r")
+ (match_operand:SI 1 "int5_operand" "L")))
+ (match_operand:QI 2 "reg_or_0_operand" "rM"))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0) (match_dup 1)))]
+ ""
+ "{stbs|stb},mb %r2,%1(%0)"
+ [(set_attr "type" "store")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (mem:QI (plus:DI (match_operand:DI 0 "register_operand" "+r")
+ (match_operand:DI 1 "int5_operand" "L")))
+ (match_operand:QI 2 "reg_or_0_operand" "rM"))
+ (set (match_dup 0)
+ (plus:DI (match_dup 0) (match_dup 1)))]
+ "TARGET_64BIT"
+ "stb,mb %r2,%1(%0)"
+ [(set_attr "type" "store")
+ (set_attr "length" "4")])
+
+;; The definition of this insn does not really explain what it does,
+;; but it should suffice that anything generated as this insn will be
+;; recognized as a movmemsi operation, and that it will not successfully
+;; combine with anything.
+(define_expand "movmemsi"
+ [(parallel [(set (match_operand:BLK 0 "" "")
+ (match_operand:BLK 1 "" ""))
+ (clobber (match_dup 4))
+ (clobber (match_dup 5))
+ (clobber (match_dup 6))
+ (clobber (match_dup 7))
+ (clobber (match_dup 8))
+ (use (match_operand:SI 2 "arith14_operand" ""))
+ (use (match_operand:SI 3 "const_int_operand" ""))])]
+ "!TARGET_64BIT && optimize > 0"
+ "
+{
+ int size, align;
+
+ /* HP provides very fast block move library routine for the PA;
+ this routine includes:
+
+ 4x4 byte at a time block moves,
+ 1x4 byte at a time with alignment checked at runtime with
+ attempts to align the source and destination as needed
+ 1x1 byte loop
+
+ With that in mind, here's the heuristics to try and guess when
+ the inlined block move will be better than the library block
+ move:
+
+ If the size isn't constant, then always use the library routines.
+
+ If the size is large in respect to the known alignment, then use
+ the library routines.
+
+ If the size is small in respect to the known alignment, then open
+ code the copy (since that will lead to better scheduling).
+
+ Else use the block move pattern. */
+
+ /* Undetermined size, use the library routine. */
+ if (GET_CODE (operands[2]) != CONST_INT)
+ FAIL;
+
+ size = INTVAL (operands[2]);
+ align = INTVAL (operands[3]);
+ align = align > 4 ? 4 : (align ? align : 1);
+
+ /* If size/alignment is large, then use the library routines. */
+ if (size / align > 16)
+ FAIL;
+
+ /* This does happen, but not often enough to worry much about. */
+ if (size / align < MOVE_RATIO (optimize_insn_for_speed_p ()))
+ FAIL;
+
+ /* Fall through means we're going to use our block move pattern. */
+ operands[0]
+ = replace_equiv_address (operands[0],
+ copy_to_mode_reg (SImode, XEXP (operands[0], 0)));
+ operands[1]
+ = replace_equiv_address (operands[1],
+ copy_to_mode_reg (SImode, XEXP (operands[1], 0)));
+ operands[4] = gen_reg_rtx (SImode);
+ operands[5] = gen_reg_rtx (SImode);
+ operands[6] = gen_reg_rtx (SImode);
+ operands[7] = gen_reg_rtx (SImode);
+ operands[8] = gen_reg_rtx (SImode);
+}")
+
+;; The operand constraints are written like this to support both compile-time
+;; and run-time determined byte counts. The expander and pa_output_block_move
+;; only support compile-time determined counts at this time.
+;;
+;; If the count is run-time determined, the register with the byte count
+;; is clobbered by the copying code, and therefore it is forced to operand 2.
+;;
+;; We used to clobber operands 0 and 1. However, a change to regrename.c
+;; broke this semantic for pseudo registers. We can't use match_scratch
+;; as this requires two registers in the class R1_REGS when the MEMs for
+;; operands 0 and 1 are both equivalent to symbolic MEMs. Thus, we are
+;; forced to internally copy operands 0 and 1 to operands 7 and 8,
+;; respectively. We then split or peephole optimize after reload.
+(define_insn "movmemsi_prereload"
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "r,r"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "r,r")))
+ (clobber (match_operand:SI 2 "register_operand" "=&r,&r")) ;loop cnt/tmp
+ (clobber (match_operand:SI 3 "register_operand" "=&r,&r")) ;item tmp1
+ (clobber (match_operand:SI 6 "register_operand" "=&r,&r")) ;item tmp2
+ (clobber (match_operand:SI 7 "register_operand" "=&r,&r")) ;item tmp3
+ (clobber (match_operand:SI 8 "register_operand" "=&r,&r")) ;item tmp4
+ (use (match_operand:SI 4 "arith14_operand" "J,2")) ;byte count
+ (use (match_operand:SI 5 "const_int_operand" "n,n"))] ;alignment
+ "!TARGET_64BIT"
+ "#"
+ [(set_attr "type" "multi,multi")])
+
+(define_split
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (match_operand:BLK 1 "memory_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" ""))
+ (clobber (match_operand:SI 3 "register_operand" ""))
+ (clobber (match_operand:SI 6 "register_operand" ""))
+ (clobber (match_operand:SI 7 "register_operand" ""))
+ (clobber (match_operand:SI 8 "register_operand" ""))
+ (use (match_operand:SI 4 "arith14_operand" ""))
+ (use (match_operand:SI 5 "const_int_operand" ""))])]
+ "!TARGET_64BIT && reload_completed && !flag_peephole2
+ && GET_CODE (operands[0]) == MEM
+ && register_operand (XEXP (operands[0], 0), SImode)
+ && GET_CODE (operands[1]) == MEM
+ && register_operand (XEXP (operands[1], 0), SImode)"
+ [(set (match_dup 7) (match_dup 9))
+ (set (match_dup 8) (match_dup 10))
+ (parallel [(set (match_dup 0) (match_dup 1))
+ (clobber (match_dup 2))
+ (clobber (match_dup 3))
+ (clobber (match_dup 6))
+ (clobber (match_dup 7))
+ (clobber (match_dup 8))
+ (use (match_dup 4))
+ (use (match_dup 5))
+ (const_int 0)])]
+ "
+{
+ operands[9] = XEXP (operands[0], 0);
+ operands[10] = XEXP (operands[1], 0);
+ operands[0] = replace_equiv_address (operands[0], operands[7]);
+ operands[1] = replace_equiv_address (operands[1], operands[8]);
+}")
+
+(define_peephole2
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (match_operand:BLK 1 "memory_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" ""))
+ (clobber (match_operand:SI 3 "register_operand" ""))
+ (clobber (match_operand:SI 6 "register_operand" ""))
+ (clobber (match_operand:SI 7 "register_operand" ""))
+ (clobber (match_operand:SI 8 "register_operand" ""))
+ (use (match_operand:SI 4 "arith14_operand" ""))
+ (use (match_operand:SI 5 "const_int_operand" ""))])]
+ "!TARGET_64BIT
+ && GET_CODE (operands[0]) == MEM
+ && register_operand (XEXP (operands[0], 0), SImode)
+ && GET_CODE (operands[1]) == MEM
+ && register_operand (XEXP (operands[1], 0), SImode)"
+ [(parallel [(set (match_dup 0) (match_dup 1))
+ (clobber (match_dup 2))
+ (clobber (match_dup 3))
+ (clobber (match_dup 6))
+ (clobber (match_dup 7))
+ (clobber (match_dup 8))
+ (use (match_dup 4))
+ (use (match_dup 5))
+ (const_int 0)])]
+ "
+{
+ rtx addr = XEXP (operands[0], 0);
+ if (dead_or_set_p (curr_insn, addr))
+ operands[7] = addr;
+ else
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[7], addr));
+ operands[0] = replace_equiv_address (operands[0], operands[7]);
+ }
+
+ addr = XEXP (operands[1], 0);
+ if (dead_or_set_p (curr_insn, addr))
+ operands[8] = addr;
+ else
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[8], addr));
+ operands[1] = replace_equiv_address (operands[1], operands[8]);
+ }
+}")
+
+(define_insn "movmemsi_postreload"
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "+r,r"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "+r,r")))
+ (clobber (match_operand:SI 2 "register_operand" "=&r,&r")) ;loop cnt/tmp
+ (clobber (match_operand:SI 3 "register_operand" "=&r,&r")) ;item tmp1
+ (clobber (match_operand:SI 6 "register_operand" "=&r,&r")) ;item tmp2
+ (clobber (match_dup 0))
+ (clobber (match_dup 1))
+ (use (match_operand:SI 4 "arith14_operand" "J,2")) ;byte count
+ (use (match_operand:SI 5 "const_int_operand" "n,n")) ;alignment
+ (const_int 0)]
+ "!TARGET_64BIT && reload_completed"
+ "* return pa_output_block_move (operands, !which_alternative);"
+ [(set_attr "type" "multi,multi")])
+
+(define_expand "movmemdi"
+ [(parallel [(set (match_operand:BLK 0 "" "")
+ (match_operand:BLK 1 "" ""))
+ (clobber (match_dup 4))
+ (clobber (match_dup 5))
+ (clobber (match_dup 6))
+ (clobber (match_dup 7))
+ (clobber (match_dup 8))
+ (use (match_operand:DI 2 "arith14_operand" ""))
+ (use (match_operand:DI 3 "const_int_operand" ""))])]
+ "TARGET_64BIT && optimize > 0"
+ "
+{
+ int size, align;
+
+ /* HP provides very fast block move library routine for the PA;
+ this routine includes:
+
+ 4x4 byte at a time block moves,
+ 1x4 byte at a time with alignment checked at runtime with
+ attempts to align the source and destination as needed
+ 1x1 byte loop
+
+ With that in mind, here's the heuristics to try and guess when
+ the inlined block move will be better than the library block
+ move:
+
+ If the size isn't constant, then always use the library routines.
+
+ If the size is large in respect to the known alignment, then use
+ the library routines.
+
+ If the size is small in respect to the known alignment, then open
+ code the copy (since that will lead to better scheduling).
+
+ Else use the block move pattern. */
+
+ /* Undetermined size, use the library routine. */
+ if (GET_CODE (operands[2]) != CONST_INT)
+ FAIL;
+
+ size = INTVAL (operands[2]);
+ align = INTVAL (operands[3]);
+ align = align > 8 ? 8 : (align ? align : 1);
+
+ /* If size/alignment is large, then use the library routines. */
+ if (size / align > 16)
+ FAIL;
+
+ /* This does happen, but not often enough to worry much about. */
+ if (size / align < MOVE_RATIO (optimize_insn_for_speed_p ()))
+ FAIL;
+
+ /* Fall through means we're going to use our block move pattern. */
+ operands[0]
+ = replace_equiv_address (operands[0],
+ copy_to_mode_reg (DImode, XEXP (operands[0], 0)));
+ operands[1]
+ = replace_equiv_address (operands[1],
+ copy_to_mode_reg (DImode, XEXP (operands[1], 0)));
+ operands[4] = gen_reg_rtx (DImode);
+ operands[5] = gen_reg_rtx (DImode);
+ operands[6] = gen_reg_rtx (DImode);
+ operands[7] = gen_reg_rtx (DImode);
+ operands[8] = gen_reg_rtx (DImode);
+}")
+
+;; The operand constraints are written like this to support both compile-time
+;; and run-time determined byte counts. The expander and pa_output_block_move
+;; only support compile-time determined counts at this time.
+;;
+;; If the count is run-time determined, the register with the byte count
+;; is clobbered by the copying code, and therefore it is forced to operand 2.
+;;
+;; We used to clobber operands 0 and 1. However, a change to regrename.c
+;; broke this semantic for pseudo registers. We can't use match_scratch
+;; as this requires two registers in the class R1_REGS when the MEMs for
+;; operands 0 and 1 are both equivalent to symbolic MEMs. Thus, we are
+;; forced to internally copy operands 0 and 1 to operands 7 and 8,
+;; respectively. We then split or peephole optimize after reload.
+(define_insn "movmemdi_prereload"
+ [(set (mem:BLK (match_operand:DI 0 "register_operand" "r,r"))
+ (mem:BLK (match_operand:DI 1 "register_operand" "r,r")))
+ (clobber (match_operand:DI 2 "register_operand" "=&r,&r")) ;loop cnt/tmp
+ (clobber (match_operand:DI 3 "register_operand" "=&r,&r")) ;item tmp1
+ (clobber (match_operand:DI 6 "register_operand" "=&r,&r")) ;item tmp2
+ (clobber (match_operand:DI 7 "register_operand" "=&r,&r")) ;item tmp3
+ (clobber (match_operand:DI 8 "register_operand" "=&r,&r")) ;item tmp4
+ (use (match_operand:DI 4 "arith14_operand" "J,2")) ;byte count
+ (use (match_operand:DI 5 "const_int_operand" "n,n"))] ;alignment
+ "TARGET_64BIT"
+ "#"
+ [(set_attr "type" "multi,multi")])
+
+(define_split
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (match_operand:BLK 1 "memory_operand" ""))
+ (clobber (match_operand:DI 2 "register_operand" ""))
+ (clobber (match_operand:DI 3 "register_operand" ""))
+ (clobber (match_operand:DI 6 "register_operand" ""))
+ (clobber (match_operand:DI 7 "register_operand" ""))
+ (clobber (match_operand:DI 8 "register_operand" ""))
+ (use (match_operand:DI 4 "arith14_operand" ""))
+ (use (match_operand:DI 5 "const_int_operand" ""))])]
+ "TARGET_64BIT && reload_completed && !flag_peephole2
+ && GET_CODE (operands[0]) == MEM
+ && register_operand (XEXP (operands[0], 0), DImode)
+ && GET_CODE (operands[1]) == MEM
+ && register_operand (XEXP (operands[1], 0), DImode)"
+ [(set (match_dup 7) (match_dup 9))
+ (set (match_dup 8) (match_dup 10))
+ (parallel [(set (match_dup 0) (match_dup 1))
+ (clobber (match_dup 2))
+ (clobber (match_dup 3))
+ (clobber (match_dup 6))
+ (clobber (match_dup 7))
+ (clobber (match_dup 8))
+ (use (match_dup 4))
+ (use (match_dup 5))
+ (const_int 0)])]
+ "
+{
+ operands[9] = XEXP (operands[0], 0);
+ operands[10] = XEXP (operands[1], 0);
+ operands[0] = replace_equiv_address (operands[0], operands[7]);
+ operands[1] = replace_equiv_address (operands[1], operands[8]);
+}")
+
+(define_peephole2
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (match_operand:BLK 1 "memory_operand" ""))
+ (clobber (match_operand:DI 2 "register_operand" ""))
+ (clobber (match_operand:DI 3 "register_operand" ""))
+ (clobber (match_operand:DI 6 "register_operand" ""))
+ (clobber (match_operand:DI 7 "register_operand" ""))
+ (clobber (match_operand:DI 8 "register_operand" ""))
+ (use (match_operand:DI 4 "arith14_operand" ""))
+ (use (match_operand:DI 5 "const_int_operand" ""))])]
+ "TARGET_64BIT
+ && GET_CODE (operands[0]) == MEM
+ && register_operand (XEXP (operands[0], 0), DImode)
+ && GET_CODE (operands[1]) == MEM
+ && register_operand (XEXP (operands[1], 0), DImode)"
+ [(parallel [(set (match_dup 0) (match_dup 1))
+ (clobber (match_dup 2))
+ (clobber (match_dup 3))
+ (clobber (match_dup 6))
+ (clobber (match_dup 7))
+ (clobber (match_dup 8))
+ (use (match_dup 4))
+ (use (match_dup 5))
+ (const_int 0)])]
+ "
+{
+ rtx addr = XEXP (operands[0], 0);
+ if (dead_or_set_p (curr_insn, addr))
+ operands[7] = addr;
+ else
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[7], addr));
+ operands[0] = replace_equiv_address (operands[0], operands[7]);
+ }
+
+ addr = XEXP (operands[1], 0);
+ if (dead_or_set_p (curr_insn, addr))
+ operands[8] = addr;
+ else
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[8], addr));
+ operands[1] = replace_equiv_address (operands[1], operands[8]);
+ }
+}")
+
+(define_insn "movmemdi_postreload"
+ [(set (mem:BLK (match_operand:DI 0 "register_operand" "+r,r"))
+ (mem:BLK (match_operand:DI 1 "register_operand" "+r,r")))
+ (clobber (match_operand:DI 2 "register_operand" "=&r,&r")) ;loop cnt/tmp
+ (clobber (match_operand:DI 3 "register_operand" "=&r,&r")) ;item tmp1
+ (clobber (match_operand:DI 6 "register_operand" "=&r,&r")) ;item tmp2
+ (clobber (match_dup 0))
+ (clobber (match_dup 1))
+ (use (match_operand:DI 4 "arith14_operand" "J,2")) ;byte count
+ (use (match_operand:DI 5 "const_int_operand" "n,n")) ;alignment
+ (const_int 0)]
+ "TARGET_64BIT && reload_completed"
+ "* return pa_output_block_move (operands, !which_alternative);"
+ [(set_attr "type" "multi,multi")])
+
+(define_expand "setmemsi"
+ [(parallel [(set (match_operand:BLK 0 "" "")
+ (match_operand 2 "const_int_operand" ""))
+ (clobber (match_dup 4))
+ (clobber (match_dup 5))
+ (use (match_operand:SI 1 "arith14_operand" ""))
+ (use (match_operand:SI 3 "const_int_operand" ""))])]
+ "!TARGET_64BIT && optimize > 0"
+ "
+{
+ int size, align;
+
+ /* If value to set is not zero, use the library routine. */
+ if (operands[2] != const0_rtx)
+ FAIL;
+
+ /* Undetermined size, use the library routine. */
+ if (GET_CODE (operands[1]) != CONST_INT)
+ FAIL;
+
+ size = INTVAL (operands[1]);
+ align = INTVAL (operands[3]);
+ align = align > 4 ? 4 : align;
+
+ /* If size/alignment is large, then use the library routines. */
+ if (size / align > 16)
+ FAIL;
+
+ /* This does happen, but not often enough to worry much about. */
+ if (size / align < MOVE_RATIO (optimize_insn_for_speed_p ()))
+ FAIL;
+
+ /* Fall through means we're going to use our block clear pattern. */
+ operands[0]
+ = replace_equiv_address (operands[0],
+ copy_to_mode_reg (SImode, XEXP (operands[0], 0)));
+ operands[4] = gen_reg_rtx (SImode);
+ operands[5] = gen_reg_rtx (SImode);
+}")
+
+(define_insn "clrmemsi_prereload"
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "r,r"))
+ (const_int 0))
+ (clobber (match_operand:SI 1 "register_operand" "=&r,&r")) ;loop cnt/tmp
+ (clobber (match_operand:SI 4 "register_operand" "=&r,&r")) ;tmp1
+ (use (match_operand:SI 2 "arith14_operand" "J,1")) ;byte count
+ (use (match_operand:SI 3 "const_int_operand" "n,n"))] ;alignment
+ "!TARGET_64BIT"
+ "#"
+ [(set_attr "type" "multi,multi")])
+
+(define_split
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (const_int 0))
+ (clobber (match_operand:SI 1 "register_operand" ""))
+ (clobber (match_operand:SI 4 "register_operand" ""))
+ (use (match_operand:SI 2 "arith14_operand" ""))
+ (use (match_operand:SI 3 "const_int_operand" ""))])]
+ "!TARGET_64BIT && reload_completed && !flag_peephole2
+ && GET_CODE (operands[0]) == MEM
+ && register_operand (XEXP (operands[0], 0), SImode)"
+ [(set (match_dup 4) (match_dup 5))
+ (parallel [(set (match_dup 0) (const_int 0))
+ (clobber (match_dup 1))
+ (clobber (match_dup 4))
+ (use (match_dup 2))
+ (use (match_dup 3))
+ (const_int 0)])]
+ "
+{
+ operands[5] = XEXP (operands[0], 0);
+ operands[0] = replace_equiv_address (operands[0], operands[4]);
+}")
+
+(define_peephole2
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (const_int 0))
+ (clobber (match_operand:SI 1 "register_operand" ""))
+ (clobber (match_operand:SI 4 "register_operand" ""))
+ (use (match_operand:SI 2 "arith14_operand" ""))
+ (use (match_operand:SI 3 "const_int_operand" ""))])]
+ "!TARGET_64BIT
+ && GET_CODE (operands[0]) == MEM
+ && register_operand (XEXP (operands[0], 0), SImode)"
+ [(parallel [(set (match_dup 0) (const_int 0))
+ (clobber (match_dup 1))
+ (clobber (match_dup 4))
+ (use (match_dup 2))
+ (use (match_dup 3))
+ (const_int 0)])]
+ "
+{
+ rtx addr = XEXP (operands[0], 0);
+ if (dead_or_set_p (curr_insn, addr))
+ operands[4] = addr;
+ else
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[4], addr));
+ operands[0] = replace_equiv_address (operands[0], operands[4]);
+ }
+}")
+
+(define_insn "clrmemsi_postreload"
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "+r,r"))
+ (const_int 0))
+ (clobber (match_operand:SI 1 "register_operand" "=&r,&r")) ;loop cnt/tmp
+ (clobber (match_dup 0))
+ (use (match_operand:SI 2 "arith14_operand" "J,1")) ;byte count
+ (use (match_operand:SI 3 "const_int_operand" "n,n")) ;alignment
+ (const_int 0)]
+ "!TARGET_64BIT && reload_completed"
+ "* return pa_output_block_clear (operands, !which_alternative);"
+ [(set_attr "type" "multi,multi")])
+
+(define_expand "setmemdi"
+ [(parallel [(set (match_operand:BLK 0 "" "")
+ (match_operand 2 "const_int_operand" ""))
+ (clobber (match_dup 4))
+ (clobber (match_dup 5))
+ (use (match_operand:DI 1 "arith14_operand" ""))
+ (use (match_operand:DI 3 "const_int_operand" ""))])]
+ "TARGET_64BIT && optimize > 0"
+ "
+{
+ int size, align;
+
+ /* If value to set is not zero, use the library routine. */
+ if (operands[2] != const0_rtx)
+ FAIL;
+
+ /* Undetermined size, use the library routine. */
+ if (GET_CODE (operands[1]) != CONST_INT)
+ FAIL;
+
+ size = INTVAL (operands[1]);
+ align = INTVAL (operands[3]);
+ align = align > 8 ? 8 : align;
+
+ /* If size/alignment is large, then use the library routines. */
+ if (size / align > 16)
+ FAIL;
+
+ /* This does happen, but not often enough to worry much about. */
+ if (size / align < MOVE_RATIO (optimize_insn_for_speed_p ()))
+ FAIL;
+
+ /* Fall through means we're going to use our block clear pattern. */
+ operands[0]
+ = replace_equiv_address (operands[0],
+ copy_to_mode_reg (DImode, XEXP (operands[0], 0)));
+ operands[4] = gen_reg_rtx (DImode);
+ operands[5] = gen_reg_rtx (DImode);
+}")
+
+(define_insn "clrmemdi_prereload"
+ [(set (mem:BLK (match_operand:DI 0 "register_operand" "r,r"))
+ (const_int 0))
+ (clobber (match_operand:DI 1 "register_operand" "=&r,&r")) ;loop cnt/tmp
+ (clobber (match_operand:DI 4 "register_operand" "=&r,&r")) ;item tmp1
+ (use (match_operand:DI 2 "arith14_operand" "J,1")) ;byte count
+ (use (match_operand:DI 3 "const_int_operand" "n,n"))] ;alignment
+ "TARGET_64BIT"
+ "#"
+ [(set_attr "type" "multi,multi")])
+
+(define_split
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (const_int 0))
+ (clobber (match_operand:DI 1 "register_operand" ""))
+ (clobber (match_operand:DI 4 "register_operand" ""))
+ (use (match_operand:DI 2 "arith14_operand" ""))
+ (use (match_operand:DI 3 "const_int_operand" ""))])]
+ "TARGET_64BIT && reload_completed && !flag_peephole2
+ && GET_CODE (operands[0]) == MEM
+ && register_operand (XEXP (operands[0], 0), DImode)"
+ [(set (match_dup 4) (match_dup 5))
+ (parallel [(set (match_dup 0) (const_int 0))
+ (clobber (match_dup 1))
+ (clobber (match_dup 4))
+ (use (match_dup 2))
+ (use (match_dup 3))
+ (const_int 0)])]
+ "
+{
+ operands[5] = XEXP (operands[0], 0);
+ operands[0] = replace_equiv_address (operands[0], operands[4]);
+}")
+
+(define_peephole2
+ [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (const_int 0))
+ (clobber (match_operand:DI 1 "register_operand" ""))
+ (clobber (match_operand:DI 4 "register_operand" ""))
+ (use (match_operand:DI 2 "arith14_operand" ""))
+ (use (match_operand:DI 3 "const_int_operand" ""))])]
+ "TARGET_64BIT
+ && GET_CODE (operands[0]) == MEM
+ && register_operand (XEXP (operands[0], 0), DImode)"
+ [(parallel [(set (match_dup 0) (const_int 0))
+ (clobber (match_dup 1))
+ (clobber (match_dup 4))
+ (use (match_dup 2))
+ (use (match_dup 3))
+ (const_int 0)])]
+ "
+{
+ rtx addr = XEXP (operands[0], 0);
+ if (dead_or_set_p (curr_insn, addr))
+ operands[4] = addr;
+ else
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[4], addr));
+ operands[0] = replace_equiv_address (operands[0], operands[4]);
+ }
+}")
+
+(define_insn "clrmemdi_postreload"
+ [(set (mem:BLK (match_operand:DI 0 "register_operand" "+r,r"))
+ (const_int 0))
+ (clobber (match_operand:DI 1 "register_operand" "=&r,&r")) ;loop cnt/tmp
+ (clobber (match_dup 0))
+ (use (match_operand:DI 2 "arith14_operand" "J,1")) ;byte count
+ (use (match_operand:DI 3 "const_int_operand" "n,n")) ;alignment
+ (const_int 0)]
+ "TARGET_64BIT && reload_completed"
+ "* return pa_output_block_clear (operands, !which_alternative);"
+ [(set_attr "type" "multi,multi")])
+
+;; Floating point move insns
+
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "general_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, DFmode, 0))
+ DONE;
+}")
+
+;; Handle DFmode input reloads requiring %r1 as a scratch register.
+(define_expand "reload_indf_r1"
+ [(set (match_operand:DF 0 "register_operand" "=Z")
+ (match_operand:DF 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=&a"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, DFmode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle DFmode input reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_indf"
+ [(set (match_operand:DF 0 "register_operand" "=Z")
+ (match_operand:DF 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:DF 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, DFmode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle DFmode output reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_outdf"
+ [(set (match_operand:DF 0 "non_hard_reg_operand" "")
+ (match_operand:DF 1 "register_operand" "Z"))
+ (clobber (match_operand:DF 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, DFmode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn ""
+ [(set (match_operand:DF 0 "move_dest_operand"
+ "=f,*r,T,?o,?Q,f,*r,*r,?*r,?f")
+ (match_operand:DF 1 "reg_or_0_or_nonsymb_mem_operand"
+ "fG,*rG,f,*r,*r,RT,o,RQ,f,*r"))]
+ "(register_operand (operands[0], DFmode)
+ || reg_or_0_operand (operands[1], DFmode))
+ && !(GET_CODE (operands[1]) == CONST_DOUBLE
+ && GET_CODE (operands[0]) == MEM)
+ && !TARGET_64BIT
+ && !TARGET_SOFT_FLOAT"
+ "*
+{
+ if ((FP_REG_P (operands[0]) || FP_REG_P (operands[1])
+ || operands[1] == CONST0_RTX (DFmode))
+ && !(REG_P (operands[0]) && REG_P (operands[1])
+ && FP_REG_P (operands[0]) ^ FP_REG_P (operands[1])))
+ return pa_output_fp_move_double (operands);
+ return pa_output_move_double (operands);
+}"
+ [(set_attr "type" "fpalu,move,fpstore,store,store,fpload,load,load,fpstore_load,store_fpload")
+ (set_attr "length" "4,8,4,8,16,4,8,16,12,12")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "indexed_memory_operand" "=R")
+ (match_operand:DF 1 "reg_or_0_operand" "f"))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && reload_completed"
+ "fstd%F0 %1,%0"
+ [(set_attr "type" "fpstore")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4")])
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 8))
+ (match_operand:SI 2 "register_operand" "")))
+ (set (mem:DF (match_dup 0))
+ (match_operand:DF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DF (plus:SI (mult:SI (match_dup 1) (const_int 8)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (mult:SI (match_dup 1) (const_int 8))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 2 "register_operand" "")
+ (mult:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 8))))
+ (set (mem:DF (match_dup 0))
+ (match_operand:DF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DF (plus:SI (mult:SI (match_dup 1) (const_int 8)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (mult:SI (match_dup 1) (const_int 8))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (mult:DI (match_operand:DI 1 "register_operand" "")
+ (const_int 8))
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:DF (match_dup 0))
+ (match_operand:DF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DF (plus:DI (mult:DI (match_dup 1) (const_int 8)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (mult:DI (match_dup 1) (const_int 8))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 2 "register_operand" "")
+ (mult:DI (match_operand:DI 1 "register_operand" "")
+ (const_int 8))))
+ (set (mem:DF (match_dup 0))
+ (match_operand:DF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DF (plus:DI (mult:DI (match_dup 1) (const_int 8)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (mult:DI (match_dup 1) (const_int 8))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (mem:DF (match_dup 0))
+ (match_operand:DF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_INDEX_P (operands[1])
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DF (plus:SI (match_dup 1) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (mem:DF (match_dup 0))
+ (match_operand:DF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_BASE_P (operands[1])
+ && REG_OK_FOR_INDEX_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DF (plus:SI (match_dup 2) (match_dup 1)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (match_dup 2) (match_dup 1)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:DF (match_dup 0))
+ (match_operand:DF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_INDEX_P (operands[1])
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DF (plus:DI (match_dup 1) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:DF (match_dup 0))
+ (match_operand:DF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_BASE_P (operands[1])
+ && REG_OK_FOR_INDEX_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DF (plus:DI (match_dup 2) (match_dup 1)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (match_dup 2) (match_dup 1)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:DF 0 "move_dest_operand"
+ "=r,?o,?Q,r,r")
+ (match_operand:DF 1 "reg_or_0_or_nonsymb_mem_operand"
+ "rG,r,r,o,RQ"))]
+ "(register_operand (operands[0], DFmode)
+ || reg_or_0_operand (operands[1], DFmode))
+ && !TARGET_64BIT
+ && TARGET_SOFT_FLOAT"
+ "*
+{
+ return pa_output_move_double (operands);
+}"
+ [(set_attr "type" "move,store,store,load,load")
+ (set_attr "length" "8,8,16,8,16")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "move_dest_operand"
+ "=!*r,*r,*r,*r,*r,Q,f,f,T")
+ (match_operand:DF 1 "move_src_operand"
+ "!*r,J,N,K,RQ,*rG,fG,RT,f"))]
+ "(register_operand (operands[0], DFmode)
+ || reg_or_0_operand (operands[1], DFmode))
+ && !TARGET_SOFT_FLOAT && TARGET_64BIT"
+ "@
+ copy %1,%0
+ ldi %1,%0
+ ldil L'%1,%0
+ depdi,z %z1,%0
+ ldd%M1 %1,%0
+ std%M0 %r1,%0
+ fcpy,dbl %f1,%0
+ fldd%F1 %1,%0
+ fstd%F0 %1,%0"
+ [(set_attr "type" "move,move,move,shift,load,store,fpalu,fpload,fpstore")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4,4,4,4,4,4,4,4")])
+
+
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, DImode, 0))
+ DONE;
+}")
+
+;; Handle DImode input reloads requiring %r1 as a scratch register.
+(define_expand "reload_indi_r1"
+ [(set (match_operand:DI 0 "register_operand" "=Z")
+ (match_operand:DI 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=&a"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, DImode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle DImode input reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_indi"
+ [(set (match_operand:DI 0 "register_operand" "=Z")
+ (match_operand:DI 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, DImode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle DImode output reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_outdi"
+ [(set (match_operand:DI 0 "non_hard_reg_operand" "")
+ (match_operand:DI 1 "register_operand" "Z"))
+ (clobber (match_operand:SI 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, DImode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (high:DI (match_operand 1 "" "")))]
+ "!TARGET_64BIT"
+ "*
+{
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+
+ switch (GET_CODE (op1))
+ {
+ case CONST_INT:
+#if HOST_BITS_PER_WIDE_INT <= 32
+ operands[0] = operand_subword (op0, 1, 0, DImode);
+ output_asm_insn (\"ldil L'%1,%0\", operands);
+
+ operands[0] = operand_subword (op0, 0, 0, DImode);
+ if (INTVAL (op1) < 0)
+ output_asm_insn (\"ldi -1,%0\", operands);
+ else
+ output_asm_insn (\"ldi 0,%0\", operands);
+#else
+ operands[0] = operand_subword (op0, 1, 0, DImode);
+ operands[1] = GEN_INT (INTVAL (op1) & 0xffffffff);
+ output_asm_insn (\"ldil L'%1,%0\", operands);
+
+ operands[0] = operand_subword (op0, 0, 0, DImode);
+ operands[1] = GEN_INT (INTVAL (op1) >> 32);
+ output_asm_insn (pa_singlemove_string (operands), operands);
+#endif
+ break;
+
+ case CONST_DOUBLE:
+ operands[0] = operand_subword (op0, 1, 0, DImode);
+ operands[1] = GEN_INT (CONST_DOUBLE_LOW (op1));
+ output_asm_insn (\"ldil L'%1,%0\", operands);
+
+ operands[0] = operand_subword (op0, 0, 0, DImode);
+ operands[1] = GEN_INT (CONST_DOUBLE_HIGH (op1));
+ output_asm_insn (pa_singlemove_string (operands), operands);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ return \"\";
+}"
+ [(set_attr "type" "move")
+ (set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "move_dest_operand"
+ "=r,o,Q,r,r,r,*f,*f,T,?r,?*f")
+ (match_operand:DI 1 "move_src_operand"
+ "rM,r,r,o*R,Q,i,*fM,RT,*f,*f,r"))]
+ "(register_operand (operands[0], DImode)
+ || reg_or_0_operand (operands[1], DImode))
+ && !TARGET_64BIT
+ && !TARGET_SOFT_FLOAT"
+ "*
+{
+ if ((FP_REG_P (operands[0]) || FP_REG_P (operands[1])
+ || operands[1] == CONST0_RTX (DFmode))
+ && !(REG_P (operands[0]) && REG_P (operands[1])
+ && FP_REG_P (operands[0]) ^ FP_REG_P (operands[1])))
+ return pa_output_fp_move_double (operands);
+ return pa_output_move_double (operands);
+}"
+ [(set_attr "type"
+ "move,store,store,load,load,multi,fpalu,fpload,fpstore,fpstore_load,store_fpload")
+ (set_attr "length" "8,8,16,8,16,16,4,4,4,12,12")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "move_dest_operand"
+ "=r,r,r,r,r,r,Q,!*q,!r,!*f,*f,T")
+ (match_operand:DI 1 "move_src_operand"
+ "A,r,J,N,K,RQ,rM,!rM,!*q,!*fM,RT,*f"))]
+ "(register_operand (operands[0], DImode)
+ || reg_or_0_operand (operands[1], DImode))
+ && !TARGET_SOFT_FLOAT && TARGET_64BIT"
+ "@
+ ldd RT'%A1,%0
+ copy %1,%0
+ ldi %1,%0
+ ldil L'%1,%0
+ depdi,z %z1,%0
+ ldd%M1 %1,%0
+ std%M0 %r1,%0
+ mtsar %r1
+ {mfctl|mfctl,w} %%sar,%0
+ fcpy,dbl %f1,%0
+ fldd%F1 %1,%0
+ fstd%F0 %1,%0"
+ [(set_attr "type" "load,move,move,move,shift,load,store,move,move,fpalu,fpload,fpstore")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "indexed_memory_operand" "=R")
+ (match_operand:DI 1 "register_operand" "f"))]
+ "!TARGET_SOFT_FLOAT
+ && TARGET_64BIT
+ && !TARGET_DISABLE_INDEXING
+ && reload_completed"
+ "fstd%F0 %1,%0"
+ [(set_attr "type" "fpstore")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4")])
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (mult:DI (match_operand:DI 1 "register_operand" "")
+ (const_int 8))
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:DI (match_dup 0))
+ (match_operand:DI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DI (plus:DI (mult:DI (match_dup 1) (const_int 8)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (mult:DI (match_dup 1) (const_int 8))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 2 "register_operand" "")
+ (mult:DI (match_operand:DI 1 "register_operand" "")
+ (const_int 8))))
+ (set (mem:DI (match_dup 0))
+ (match_operand:DI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DI (plus:DI (mult:DI (match_dup 1) (const_int 8)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (mult:DI (match_dup 1) (const_int 8))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:DI (match_dup 0))
+ (match_operand:DI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_INDEX_P (operands[1])
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DI (plus:DI (match_dup 1) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:DI (match_dup 0))
+ (match_operand:DI 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_BASE_P (operands[1])
+ && REG_OK_FOR_INDEX_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:DI (plus:DI (match_dup 2) (match_dup 1)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (match_dup 2) (match_dup 1)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "move_dest_operand"
+ "=r,o,Q,r,r,r")
+ (match_operand:DI 1 "general_operand"
+ "rM,r,r,o,Q,i"))]
+ "(register_operand (operands[0], DImode)
+ || reg_or_0_operand (operands[1], DImode))
+ && !TARGET_64BIT
+ && TARGET_SOFT_FLOAT"
+ "*
+{
+ return pa_output_move_double (operands);
+}"
+ [(set_attr "type" "move,store,store,load,load,multi")
+ (set_attr "length" "8,8,16,8,16,16")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,&r")
+ (lo_sum:DI (match_operand:DI 1 "register_operand" "0,r")
+ (match_operand:DI 2 "immediate_operand" "i,i")))]
+ "!TARGET_64BIT"
+ "*
+{
+ /* Don't output a 64-bit constant, since we can't trust the assembler to
+ handle it correctly. */
+ if (GET_CODE (operands[2]) == CONST_DOUBLE)
+ operands[2] = GEN_INT (CONST_DOUBLE_LOW (operands[2]));
+ else if (HOST_BITS_PER_WIDE_INT > 32
+ && GET_CODE (operands[2]) == CONST_INT)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffffffff);
+ if (which_alternative == 1)
+ output_asm_insn (\"copy %1,%0\", operands);
+ return \"ldo R'%G2(%R1),%R0\";
+}"
+ [(set_attr "type" "move,move")
+ (set_attr "length" "4,8")])
+
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "general_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, SFmode, 0))
+ DONE;
+}")
+
+;; Handle SFmode input reloads requiring %r1 as a scratch register.
+(define_expand "reload_insf_r1"
+ [(set (match_operand:SF 0 "register_operand" "=Z")
+ (match_operand:SF 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=&a"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, SFmode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle SFmode input reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_insf"
+ [(set (match_operand:SF 0 "register_operand" "=Z")
+ (match_operand:SF 1 "non_hard_reg_operand" ""))
+ (clobber (match_operand:SF 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, SFmode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+;; Handle SFmode output reloads requiring a general register as a
+;; scratch register.
+(define_expand "reload_outsf"
+ [(set (match_operand:SF 0 "non_hard_reg_operand" "")
+ (match_operand:SF 1 "register_operand" "Z"))
+ (clobber (match_operand:SF 2 "register_operand" "=&r"))]
+ ""
+ "
+{
+ if (pa_emit_move_sequence (operands, SFmode, operands[2]))
+ DONE;
+
+ /* We don't want the clobber emitted, so handle this ourselves. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "move_dest_operand"
+ "=f,!*r,f,*r,T,Q,?*r,?f")
+ (match_operand:SF 1 "reg_or_0_or_nonsymb_mem_operand"
+ "fG,!*rG,RT,RQ,f,*rG,f,*r"))]
+ "(register_operand (operands[0], SFmode)
+ || reg_or_0_operand (operands[1], SFmode))
+ && !TARGET_SOFT_FLOAT
+ && !TARGET_64BIT"
+ "@
+ fcpy,sgl %f1,%0
+ copy %r1,%0
+ fldw%F1 %1,%0
+ ldw%M1 %1,%0
+ fstw%F0 %1,%0
+ stw%M0 %r1,%0
+ {fstws|fstw} %1,-16(%%sp)\n\t{ldws|ldw} -16(%%sp),%0
+ {stws|stw} %1,-16(%%sp)\n\t{fldws|fldw} -16(%%sp),%0"
+ [(set_attr "type" "fpalu,move,fpload,load,fpstore,store,fpstore_load,store_fpload")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4,4,4,4,4,8,8")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "move_dest_operand"
+ "=f,!*r,f,*r,T,Q")
+ (match_operand:SF 1 "reg_or_0_or_nonsymb_mem_operand"
+ "fG,!*rG,RT,RQ,f,*rG"))]
+ "(register_operand (operands[0], SFmode)
+ || reg_or_0_operand (operands[1], SFmode))
+ && !TARGET_SOFT_FLOAT
+ && TARGET_64BIT"
+ "@
+ fcpy,sgl %f1,%0
+ copy %r1,%0
+ fldw%F1 %1,%0
+ ldw%M1 %1,%0
+ fstw%F0 %1,%0
+ stw%M0 %r1,%0"
+ [(set_attr "type" "fpalu,move,fpload,load,fpstore,store")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4,4,4,4,4")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "indexed_memory_operand" "=R")
+ (match_operand:SF 1 "register_operand" "f"))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && reload_completed"
+ "fstw%F0 %1,%0"
+ [(set_attr "type" "fpstore")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4")])
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 4))
+ (match_operand:SI 2 "register_operand" "")))
+ (set (mem:SF (match_dup 0))
+ (match_operand:SF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SF (plus:SI (mult:SI (match_dup 1) (const_int 4)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (mult:SI (match_dup 1) (const_int 4))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 2 "register_operand" "")
+ (mult:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 4))))
+ (set (mem:SF (match_dup 0))
+ (match_operand:SF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SF (plus:SI (mult:SI (match_dup 1) (const_int 4)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (mult:SI (match_dup 1) (const_int 4))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (mult:DI (match_operand:DI 1 "register_operand" "")
+ (const_int 4))
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:SF (match_dup 0))
+ (match_operand:SF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SF (plus:DI (mult:DI (match_dup 1) (const_int 4)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (mult:DI (match_dup 1) (const_int 4))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 2 "register_operand" "")
+ (mult:DI (match_operand:DI 1 "register_operand" "")
+ (const_int 4))))
+ (set (mem:SF (match_dup 0))
+ (match_operand:SF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SF (plus:DI (mult:DI (match_dup 1) (const_int 4)) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (mult:DI (match_dup 1) (const_int 4))
+ (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (mem:SF (match_dup 0))
+ (match_operand:SF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_INDEX_P (operands[1])
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SF (plus:SI (match_dup 1) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (mem:SF (match_dup 0))
+ (match_operand:SF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_BASE_P (operands[1])
+ && REG_OK_FOR_INDEX_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SF (plus:SI (match_dup 2) (match_dup 1)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:SI (match_dup 2) (match_dup 1)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:SF (match_dup 0))
+ (match_operand:SF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_INDEX_P (operands[1])
+ && REG_OK_FOR_BASE_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SF (plus:DI (match_dup 1) (match_dup 2)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))]
+ "")
+
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (mem:SF (match_dup 0))
+ (match_operand:SF 3 "register_operand" ""))]
+ "!TARGET_SOFT_FLOAT
+ && !TARGET_DISABLE_INDEXING
+ && TARGET_64BIT
+ && TARGET_NO_SPACE_REGS
+ && REG_OK_FOR_BASE_P (operands[1])
+ && REG_OK_FOR_INDEX_P (operands[2])
+ && FP_REGNO_P (REGNO (operands[3]))"
+ [(set (mem:SF (plus:DI (match_dup 2) (match_dup 1)))
+ (match_dup 3))
+ (set (match_dup 0) (plus:DI (match_dup 2) (match_dup 1)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "move_dest_operand"
+ "=r,r,Q")
+ (match_operand:SF 1 "reg_or_0_or_nonsymb_mem_operand"
+ "rG,RQ,rG"))]
+ "(register_operand (operands[0], SFmode)
+ || reg_or_0_operand (operands[1], SFmode))
+ && TARGET_SOFT_FLOAT"
+ "@
+ copy %r1,%0
+ ldw%M1 %1,%0
+ stw%M0 %r1,%0"
+ [(set_attr "type" "move,load,store")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4,4")])
+
+
+
+;;- zero extension instructions
+;; We have define_expand for zero extension patterns to make sure the
+;; operands get loaded into registers. The define_insns accept
+;; memory operands. This gives us better overall code than just
+;; having a pattern that does or does not accept memory operands.
+
+(define_expand "zero_extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (zero_extend:HI
+ (match_operand:QI 1 "register_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (zero_extend:HI
+ (match_operand:QI 1 "move_src_operand" "r,RQ")))]
+ "GET_CODE (operands[1]) != CONST_INT"
+ "@
+ {extru|extrw,u} %1,31,8,%0
+ ldb%M1 %1,%0"
+ [(set_attr "type" "shift,load")
+ (set_attr "length" "4,4")])
+
+(define_expand "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI
+ (match_operand:QI 1 "register_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI
+ (match_operand:QI 1 "move_src_operand" "r,RQ")))]
+ "GET_CODE (operands[1]) != CONST_INT"
+ "@
+ {extru|extrw,u} %1,31,8,%0
+ ldb%M1 %1,%0"
+ [(set_attr "type" "shift,load")
+ (set_attr "length" "4,4")])
+
+(define_expand "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI
+ (match_operand:HI 1 "register_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI
+ (match_operand:HI 1 "move_src_operand" "r,RQ")))]
+ "GET_CODE (operands[1]) != CONST_INT"
+ "@
+ {extru|extrw,u} %1,31,16,%0
+ ldh%M1 %1,%0"
+ [(set_attr "type" "shift,load")
+ (set_attr "length" "4,4")])
+
+(define_expand "zero_extendqidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extend:DI
+ (match_operand:QI 1 "register_operand" "")))]
+ "TARGET_64BIT"
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (zero_extend:DI
+ (match_operand:QI 1 "move_src_operand" "r,RQ")))]
+ "TARGET_64BIT && GET_CODE (operands[1]) != CONST_INT"
+ "@
+ extrd,u %1,63,8,%0
+ ldb%M1 %1,%0"
+ [(set_attr "type" "shift,load")
+ (set_attr "length" "4,4")])
+
+(define_expand "zero_extendhidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extend:DI
+ (match_operand:HI 1 "register_operand" "")))]
+ "TARGET_64BIT"
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (zero_extend:DI
+ (match_operand:HI 1 "move_src_operand" "r,RQ")))]
+ "TARGET_64BIT && GET_CODE (operands[1]) != CONST_INT"
+ "@
+ extrd,u %1,63,16,%0
+ ldh%M1 %1,%0"
+ [(set_attr "type" "shift,load")
+ (set_attr "length" "4,4")])
+
+(define_expand "zero_extendsidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extend:DI
+ (match_operand:SI 1 "register_operand" "")))]
+ "TARGET_64BIT"
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (zero_extend:DI
+ (match_operand:SI 1 "move_src_operand" "r,RQ")))]
+ "TARGET_64BIT && GET_CODE (operands[1]) != CONST_INT"
+ "@
+ extrd,u %1,63,32,%0
+ ldw%M1 %1,%0"
+ [(set_attr "type" "shift,load")
+ (set_attr "length" "4,4")])
+
+;;- sign extension instructions
+
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))]
+ ""
+ "{extrs|extrw,s} %1,31,16,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))]
+ ""
+ "{extrs|extrw,s} %1,31,8,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))]
+ ""
+ "{extrs|extrw,s} %1,31,8,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "extendqidi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (match_operand:QI 1 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "extrd,s %1,63,8,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "extendhidi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (match_operand:HI 1 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "extrd,s %1,63,16,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "extendsidi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (match_operand:SI 1 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "extrd,s %1,63,32,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+
+;; Conversions between float and double.
+
+(define_insn "extendsfdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (float_extend:DF
+ (match_operand:SF 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "{fcnvff|fcnv},sgl,dbl %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "truncdfsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float_truncate:SF
+ (match_operand:DF 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "{fcnvff|fcnv},dbl,sgl %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+;; Conversion between fixed point and floating point.
+;; Note that among the fix-to-float insns
+;; the ones that start with SImode come first.
+;; That is so that an operand that is a CONST_INT
+;; (and therefore lacks a specific machine mode).
+;; will be recognized as SImode (which is always valid)
+;; rather than as QImode or HImode.
+
+;; This pattern forces (set (reg:SF ...) (float:SF (const_int ...)))
+;; to be reloaded by putting the constant into memory.
+;; It must come before the more general floatsisf2 pattern.
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float:SF (match_operand:SI 1 "const_int_operand" "m")))]
+ "! TARGET_SOFT_FLOAT"
+ "fldw%F1 %1,%0\;{fcnvxf,sgl,sgl|fcnv,w,sgl} %0,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "8")])
+
+(define_insn "floatsisf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float:SF (match_operand:SI 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "{fcnvxf,sgl,sgl|fcnv,w,sgl} %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+;; This pattern forces (set (reg:DF ...) (float:DF (const_int ...)))
+;; to be reloaded by putting the constant into memory.
+;; It must come before the more general floatsidf2 pattern.
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (float:DF (match_operand:SI 1 "const_int_operand" "m")))]
+ "! TARGET_SOFT_FLOAT"
+ "fldw%F1 %1,%0\;{fcnvxf,sgl,dbl|fcnv,w,dbl} %0,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "8")])
+
+(define_insn "floatsidf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (float:DF (match_operand:SI 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "{fcnvxf,sgl,dbl|fcnv,w,dbl} %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_expand "floatunssisf2"
+ [(set (subreg:SI (match_dup 2) 4)
+ (match_operand:SI 1 "register_operand" ""))
+ (set (subreg:SI (match_dup 2) 0)
+ (const_int 0))
+ (set (match_operand:SF 0 "register_operand" "")
+ (float:SF (match_dup 2)))]
+ "TARGET_PA_11 && ! TARGET_SOFT_FLOAT"
+ "
+{
+ if (TARGET_PA_20)
+ {
+ emit_insn (gen_floatunssisf2_pa20 (operands[0], operands[1]));
+ DONE;
+ }
+ operands[2] = gen_reg_rtx (DImode);
+}")
+
+(define_expand "floatunssidf2"
+ [(set (subreg:SI (match_dup 2) 4)
+ (match_operand:SI 1 "register_operand" ""))
+ (set (subreg:SI (match_dup 2) 0)
+ (const_int 0))
+ (set (match_operand:DF 0 "register_operand" "")
+ (float:DF (match_dup 2)))]
+ "TARGET_PA_11 && ! TARGET_SOFT_FLOAT"
+ "
+{
+ if (TARGET_PA_20)
+ {
+ emit_insn (gen_floatunssidf2_pa20 (operands[0], operands[1]));
+ DONE;
+ }
+ operands[2] = gen_reg_rtx (DImode);
+}")
+
+(define_insn "floatdisf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float:SF (match_operand:DI 1 "register_operand" "f")))]
+ "TARGET_PA_11 && ! TARGET_SOFT_FLOAT"
+ "{fcnvxf,dbl,sgl|fcnv,dw,sgl} %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "floatdidf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (float:DF (match_operand:DI 1 "register_operand" "f")))]
+ "TARGET_PA_11 && ! TARGET_SOFT_FLOAT"
+ "{fcnvxf,dbl,dbl|fcnv,dw,dbl} %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+;; Convert a float to an actual integer.
+;; Truncation is performed as part of the conversion.
+
+(define_insn "fix_truncsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))]
+ "! TARGET_SOFT_FLOAT"
+ "{fcnvfxt,sgl,sgl|fcnv,t,sgl,w} %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "fix_truncdfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))]
+ "! TARGET_SOFT_FLOAT"
+ "{fcnvfxt,dbl,sgl|fcnv,t,dbl,w} %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "fix_truncsfdi2"
+ [(set (match_operand:DI 0 "register_operand" "=f")
+ (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f"))))]
+ "TARGET_PA_11 && ! TARGET_SOFT_FLOAT"
+ "{fcnvfxt,sgl,dbl|fcnv,t,sgl,dw} %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "fix_truncdfdi2"
+ [(set (match_operand:DI 0 "register_operand" "=f")
+ (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f"))))]
+ "TARGET_PA_11 && ! TARGET_SOFT_FLOAT"
+ "{fcnvfxt,dbl,dbl|fcnv,t,dbl,dw} %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "floatunssidf2_pa20"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unsigned_float:DF (match_operand:SI 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT && TARGET_PA_20"
+ "fcnv,uw,dbl %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "floatunssisf2_pa20"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (unsigned_float:SF (match_operand:SI 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT && TARGET_PA_20"
+ "fcnv,uw,sgl %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "floatunsdisf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (unsigned_float:SF (match_operand:DI 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT && TARGET_PA_20"
+ "fcnv,udw,sgl %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "floatunsdidf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unsigned_float:DF (match_operand:DI 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT && TARGET_PA_20"
+ "fcnv,udw,dbl %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "fixuns_truncsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (unsigned_fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))]
+ "! TARGET_SOFT_FLOAT && TARGET_PA_20"
+ "fcnv,t,sgl,uw %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "fixuns_truncdfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (unsigned_fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))]
+ "! TARGET_SOFT_FLOAT && TARGET_PA_20"
+ "fcnv,t,dbl,uw %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "fixuns_truncsfdi2"
+ [(set (match_operand:DI 0 "register_operand" "=f")
+ (unsigned_fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f"))))]
+ "! TARGET_SOFT_FLOAT && TARGET_PA_20"
+ "fcnv,t,sgl,udw %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "fixuns_truncdfdi2"
+ [(set (match_operand:DI 0 "register_operand" "=f")
+ (unsigned_fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f"))))]
+ "! TARGET_SOFT_FLOAT && TARGET_PA_20"
+ "fcnv,t,dbl,udw %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+;;- arithmetic instructions
+
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "adddi3_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "register_operand" "%r")
+ (match_operand:DI 2 "arith11_operand" "rI")))]
+ "!TARGET_64BIT"
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ if (INTVAL (operands[2]) >= 0)
+ return \"addi %2,%R1,%R0\;{addc|add,c} %1,%%r0,%0\";
+ else
+ return \"addi %2,%R1,%R0\;{subb|sub,b} %1,%%r0,%0\";
+ }
+ else
+ return \"add %R2,%R1,%R0\;{addc|add,c} %2,%1,%0\";
+}"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (plus:DI (match_operand:DI 1 "register_operand" "%r,r")
+ (match_operand:DI 2 "arith14_operand" "r,J")))]
+ "TARGET_64BIT"
+ "@
+ add,l %1,%2,%0
+ ldo %2(%1),%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (not:DI (match_operand:DI 1 "register_operand" "r"))
+ (match_operand:DI 2 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "uaddcm %2,%1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (not:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r")))]
+ ""
+ "uaddcm %2,%1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+(define_expand "addvdi3"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "reg_or_0_operand" "")
+ (match_operand:DI 2 "arith11_operand" "")))
+ (trap_if (ne (plus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (plus:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))])]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (plus:DI (match_operand:DI 1 "reg_or_0_operand" "%rM,rM")
+ (match_operand:DI 2 "arith11_operand" "r,I")))
+ (trap_if (ne (plus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (plus:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ "TARGET_64BIT"
+ "@
+ add,tsv,* %2,%1,%0
+ addi,tsv,* %2,%1,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "length" "4,4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "reg_or_0_operand" "%rM")
+ (match_operand:DI 2 "arith11_operand" "rI")))
+ (trap_if (ne (plus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (plus:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ "!TARGET_64BIT"
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ if (INTVAL (operands[2]) >= 0)
+ return \"addi %2,%R1,%R0\;{addco|add,c,tsv} %1,%%r0,%0\";
+ else
+ return \"addi %2,%R1,%R0\;{subbo|sub,b,tsv} %1,%%r0,%0\";
+ }
+ else
+ return \"add %R2,%R1,%R0\;{addco|add,c,tsv} %2,%1,%0\";
+}"
+ [(set_attr "type" "binary")
+ (set_attr "length" "8")])
+
+;; define_splits to optimize cases of adding a constant integer
+;; to a register when the constant does not fit in 14 bits. */
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))
+ (clobber (match_operand:SI 4 "register_operand" ""))]
+ "! pa_cint_ok_for_move (INTVAL (operands[2]))
+ && VAL_14_BITS_P (INTVAL (operands[2]) >> 1)"
+ [(set (match_dup 4) (plus:SI (match_dup 1) (match_dup 2)))
+ (set (match_dup 0) (plus:SI (match_dup 4) (match_dup 3)))]
+ "
+{
+ int val = INTVAL (operands[2]);
+ int low = (val < 0) ? -0x2000 : 0x1fff;
+ int rest = val - low;
+
+ operands[2] = GEN_INT (rest);
+ operands[3] = GEN_INT (low);
+}")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))
+ (clobber (match_operand:SI 4 "register_operand" ""))]
+ "! pa_cint_ok_for_move (INTVAL (operands[2]))"
+ [(set (match_dup 4) (match_dup 2))
+ (set (match_dup 0) (plus:SI (mult:SI (match_dup 4) (match_dup 3))
+ (match_dup 1)))]
+ "
+{
+ HOST_WIDE_INT intval = INTVAL (operands[2]);
+
+ /* Try dividing the constant by 2, then 4, and finally 8 to see
+ if we can get a constant which can be loaded into a register
+ in a single instruction (pa_cint_ok_for_move).
+
+ If that fails, try to negate the constant and subtract it
+ from our input operand. */
+ if (intval % 2 == 0 && pa_cint_ok_for_move (intval / 2))
+ {
+ operands[2] = GEN_INT (intval / 2);
+ operands[3] = const2_rtx;
+ }
+ else if (intval % 4 == 0 && pa_cint_ok_for_move (intval / 4))
+ {
+ operands[2] = GEN_INT (intval / 4);
+ operands[3] = GEN_INT (4);
+ }
+ else if (intval % 8 == 0 && pa_cint_ok_for_move (intval / 8))
+ {
+ operands[2] = GEN_INT (intval / 8);
+ operands[3] = GEN_INT (8);
+ }
+ else if (pa_cint_ok_for_move (-intval))
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[4], GEN_INT (-intval)));
+ emit_insn (gen_subsi3 (operands[0], operands[1], operands[4]));
+ DONE;
+ }
+ else
+ FAIL;
+}")
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%r,r")
+ (match_operand:SI 2 "arith14_operand" "r,J")))]
+ ""
+ "@
+ {addl|add,l} %1,%2,%0
+ ldo %2(%1),%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "pa_combine_type" "addmove")
+ (set_attr "length" "4,4")])
+
+(define_insn "addvsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (plus:SI (match_operand:SI 1 "reg_or_0_operand" "%rM,rM")
+ (match_operand:SI 2 "arith11_operand" "r,I")))
+ (trap_if (ne (plus:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (sign_extend:DI (plus:SI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ ""
+ "@
+ {addo|add,tsv} %2,%1,%0
+ {addio|addi,tsv} %2,%1,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "length" "4,4")])
+
+(define_expand "subdi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (minus:DI (match_operand:DI 1 "arith11_operand" "")
+ (match_operand:DI 2 "reg_or_0_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r,!q")
+ (minus:DI (match_operand:DI 1 "arith11_operand" "r,I,!U")
+ (match_operand:DI 2 "reg_or_0_operand" "rM,rM,!rM")))]
+ "TARGET_64BIT"
+ "@
+ sub %1,%2,%0
+ subi %1,%2,%0
+ mtsarcm %2"
+ [(set_attr "type" "binary,binary,move")
+ (set_attr "length" "4,4,4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,&r")
+ (minus:DI (match_operand:DI 1 "arith11_operand" "r,I")
+ (match_operand:DI 2 "reg_or_0_operand" "rM,rM")))]
+ "!TARGET_64BIT"
+ "*
+{
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ if (INTVAL (operands[1]) >= 0)
+ return \"subi %1,%R2,%R0\;{subb|sub,b} %%r0,%2,%0\";
+ else
+ return \"ldi -1,%0\;subi %1,%R2,%R0\;{subb|sub,b} %0,%2,%0\";
+ }
+ else
+ return \"sub %R1,%R2,%R0\;{subb|sub,b} %1,%2,%0\";
+}"
+ [(set_attr "type" "binary")
+ (set (attr "length")
+ (if_then_else (eq_attr "alternative" "0")
+ (const_int 8)
+ (if_then_else (ge (symbol_ref "INTVAL (operands[1])")
+ (const_int 0))
+ (const_int 8)
+ (const_int 12))))])
+
+(define_expand "subvdi3"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "")
+ (minus:DI (match_operand:DI 1 "arith11_operand" "")
+ (match_operand:DI 2 "reg_or_0_operand" "")))
+ (trap_if (ne (minus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (minus:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))])]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (minus:DI (match_operand:DI 1 "arith11_operand" "r,I")
+ (match_operand:DI 2 "reg_or_0_operand" "rM,rM")))
+ (trap_if (ne (minus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (minus:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ "TARGET_64BIT"
+ "@
+ {subo|sub,tsv} %1,%2,%0
+ {subio|subi,tsv} %1,%2,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "length" "4,4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,&r")
+ (minus:DI (match_operand:DI 1 "arith11_operand" "r,I")
+ (match_operand:DI 2 "reg_or_0_operand" "rM,rM")))
+ (trap_if (ne (minus:TI (sign_extend:TI (match_dup 1))
+ (sign_extend:TI (match_dup 2)))
+ (sign_extend:TI (minus:DI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ "!TARGET_64BIT"
+ "*
+{
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ if (INTVAL (operands[1]) >= 0)
+ return \"subi %1,%R2,%R0\;{subbo|sub,b,tsv} %%r0,%2,%0\";
+ else
+ return \"ldi -1,%0\;subi %1,%R2,%R0\;{subbo|sub,b,tsv} %0,%2,%0\";
+ }
+ else
+ return \"sub %R1,%R2,%R0\;{subbo|sub,b,tsv} %1,%2,%0\";
+}"
+ [(set_attr "type" "binary,binary")
+ (set (attr "length")
+ (if_then_else (eq_attr "alternative" "0")
+ (const_int 8)
+ (if_then_else (ge (symbol_ref "INTVAL (operands[1])")
+ (const_int 0))
+ (const_int 8)
+ (const_int 12))))])
+
+(define_expand "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (minus:SI (match_operand:SI 1 "arith11_operand" "")
+ (match_operand:SI 2 "register_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "arith11_operand" "r,I")
+ (match_operand:SI 2 "register_operand" "r,r")))]
+ "!TARGET_PA_20"
+ "@
+ sub %1,%2,%0
+ subi %1,%2,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "length" "4,4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r,!q")
+ (minus:SI (match_operand:SI 1 "arith11_operand" "r,I,!S")
+ (match_operand:SI 2 "register_operand" "r,r,!r")))]
+ "TARGET_PA_20"
+ "@
+ sub %1,%2,%0
+ subi %1,%2,%0
+ mtsarcm %2"
+ [(set_attr "type" "binary,binary,move")
+ (set_attr "length" "4,4,4")])
+
+(define_insn "subvsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "arith11_operand" "rM,I")
+ (match_operand:SI 2 "reg_or_0_operand" "rM,rM")))
+ (trap_if (ne (minus:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (sign_extend:DI (minus:SI (match_dup 1)
+ (match_dup 2))))
+ (const_int 0))]
+ ""
+ "@
+ {subo|sub,tsv} %1,%2,%0
+ {subio|subi,tsv} %1,%2,%0"
+ [(set_attr "type" "binary,binary")
+ (set_attr "length" "4,4")])
+
+;; Clobbering a "register_operand" instead of a match_scratch
+;; in operand3 of millicode calls avoids spilling %r1 and
+;; produces better code.
+
+;; The mulsi3 insns set up registers for the millicode call.
+(define_expand "mulsi3"
+ [(set (reg:SI 26) (match_operand:SI 1 "move_src_operand" ""))
+ (set (reg:SI 25) (match_operand:SI 2 "move_src_operand" ""))
+ (parallel [(set (reg:SI 29) (mult:SI (reg:SI 26) (reg:SI 25)))
+ (clobber (match_dup 3))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (match_dup 4))])
+ (set (match_operand:SI 0 "move_dest_operand" "") (reg:SI 29))]
+ ""
+ "
+{
+ operands[4] = gen_rtx_REG (SImode, TARGET_64BIT ? 2 : 31);
+ if (TARGET_PA_11 && !TARGET_DISABLE_FPREGS && !TARGET_SOFT_FLOAT)
+ {
+ rtx scratch = gen_reg_rtx (DImode);
+ operands[1] = force_reg (SImode, operands[1]);
+ operands[2] = force_reg (SImode, operands[2]);
+ emit_insn (gen_umulsidi3 (scratch, operands[1], operands[2]));
+ emit_insn (gen_movsi (operands[0],
+ gen_rtx_SUBREG (SImode, scratch,
+ GET_MODE_SIZE (SImode))));
+ DONE;
+ }
+ operands[3] = gen_reg_rtx (SImode);
+}")
+
+(define_insn "umulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=f")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "f"))
+ (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "f"))))]
+ "TARGET_PA_11 && ! TARGET_DISABLE_FPREGS && ! TARGET_SOFT_FLOAT"
+ "xmpyu %1,%2,%0"
+ [(set_attr "type" "fpmuldbl")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=f")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "f"))
+ (match_operand:DI 2 "uint32_operand" "f")))]
+ "TARGET_PA_11 && ! TARGET_DISABLE_FPREGS && ! TARGET_SOFT_FLOAT && !TARGET_64BIT"
+ "xmpyu %1,%R2,%0"
+ [(set_attr "type" "fpmuldbl")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=f")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "f"))
+ (match_operand:DI 2 "uint32_operand" "f")))]
+ "TARGET_PA_11 && ! TARGET_DISABLE_FPREGS && ! TARGET_SOFT_FLOAT && TARGET_64BIT"
+ "xmpyu %1,%2R,%0"
+ [(set_attr "type" "fpmuldbl")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (reg:SI 29) (mult:SI (reg:SI 26) (reg:SI 25)))
+ (clobber (match_operand:SI 0 "register_operand" "=a"))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (reg:SI 31))]
+ "!TARGET_64BIT"
+ "* return pa_output_mul_insn (0, insn);"
+ [(set_attr "type" "milli")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_millicode_call (insn)")))])
+
+(define_insn ""
+ [(set (reg:SI 29) (mult:SI (reg:SI 26) (reg:SI 25)))
+ (clobber (match_operand:SI 0 "register_operand" "=a"))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (reg:SI 2))]
+ "TARGET_64BIT"
+ "* return pa_output_mul_insn (0, insn);"
+ [(set_attr "type" "milli")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_millicode_call (insn)")))])
+
+(define_expand "muldi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (mult:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))]
+ "TARGET_64BIT && ! TARGET_DISABLE_FPREGS && ! TARGET_SOFT_FLOAT"
+ "
+{
+ rtx low_product = gen_reg_rtx (DImode);
+ rtx cross_product1 = gen_reg_rtx (DImode);
+ rtx cross_product2 = gen_reg_rtx (DImode);
+ rtx cross_scratch = gen_reg_rtx (DImode);
+ rtx cross_product = gen_reg_rtx (DImode);
+ rtx op1l, op1r, op2l, op2r;
+ rtx op1shifted, op2shifted;
+
+ op1shifted = gen_reg_rtx (DImode);
+ op2shifted = gen_reg_rtx (DImode);
+ op1l = gen_reg_rtx (SImode);
+ op1r = gen_reg_rtx (SImode);
+ op2l = gen_reg_rtx (SImode);
+ op2r = gen_reg_rtx (SImode);
+
+ emit_move_insn (op1shifted, gen_rtx_LSHIFTRT (DImode, operands[1],
+ GEN_INT (32)));
+ emit_move_insn (op2shifted, gen_rtx_LSHIFTRT (DImode, operands[2],
+ GEN_INT (32)));
+ op1r = force_reg (SImode, gen_rtx_SUBREG (SImode, operands[1], 4));
+ op2r = force_reg (SImode, gen_rtx_SUBREG (SImode, operands[2], 4));
+ op1l = force_reg (SImode, gen_rtx_SUBREG (SImode, op1shifted, 4));
+ op2l = force_reg (SImode, gen_rtx_SUBREG (SImode, op2shifted, 4));
+
+ /* Emit multiplies for the cross products. */
+ emit_insn (gen_umulsidi3 (cross_product1, op2r, op1l));
+ emit_insn (gen_umulsidi3 (cross_product2, op2l, op1r));
+
+ /* Emit a multiply for the low sub-word. */
+ emit_insn (gen_umulsidi3 (low_product, copy_rtx (op2r), copy_rtx (op1r)));
+
+ /* Sum the cross products and shift them into proper position. */
+ emit_insn (gen_adddi3 (cross_scratch, cross_product1, cross_product2));
+ emit_insn (gen_ashldi3 (cross_product, cross_scratch, GEN_INT (32)));
+
+ /* Add the cross product to the low product and store the result
+ into the output operand . */
+ emit_insn (gen_adddi3 (operands[0], cross_product, low_product));
+ DONE;
+}")
+
+;;; Division and mod.
+(define_expand "divsi3"
+ [(set (reg:SI 26) (match_operand:SI 1 "move_src_operand" ""))
+ (set (reg:SI 25) (match_operand:SI 2 "move_src_operand" ""))
+ (parallel [(set (reg:SI 29) (div:SI (reg:SI 26) (reg:SI 25)))
+ (clobber (match_dup 3))
+ (clobber (match_dup 4))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (match_dup 5))])
+ (set (match_operand:SI 0 "move_dest_operand" "") (reg:SI 29))]
+ ""
+ "
+{
+ operands[3] = gen_reg_rtx (SImode);
+ if (TARGET_64BIT)
+ {
+ operands[5] = gen_rtx_REG (SImode, 2);
+ operands[4] = operands[5];
+ }
+ else
+ {
+ operands[5] = gen_rtx_REG (SImode, 31);
+ operands[4] = gen_reg_rtx (SImode);
+ }
+ if (GET_CODE (operands[2]) == CONST_INT && pa_emit_hpdiv_const (operands, 0))
+ DONE;
+}")
+
+(define_insn ""
+ [(set (reg:SI 29)
+ (div:SI (reg:SI 26) (match_operand:SI 0 "div_operand" "")))
+ (clobber (match_operand:SI 1 "register_operand" "=a"))
+ (clobber (match_operand:SI 2 "register_operand" "=&r"))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (reg:SI 31))]
+ "!TARGET_64BIT"
+ "*
+ return pa_output_div_insn (operands, 0, insn);"
+ [(set_attr "type" "milli")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_millicode_call (insn)")))])
+
+(define_insn ""
+ [(set (reg:SI 29)
+ (div:SI (reg:SI 26) (match_operand:SI 0 "div_operand" "")))
+ (clobber (match_operand:SI 1 "register_operand" "=a"))
+ (clobber (match_operand:SI 2 "register_operand" "=&r"))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (reg:SI 2))]
+ "TARGET_64BIT"
+ "*
+ return pa_output_div_insn (operands, 0, insn);"
+ [(set_attr "type" "milli")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_millicode_call (insn)")))])
+
+(define_expand "udivsi3"
+ [(set (reg:SI 26) (match_operand:SI 1 "move_src_operand" ""))
+ (set (reg:SI 25) (match_operand:SI 2 "move_src_operand" ""))
+ (parallel [(set (reg:SI 29) (udiv:SI (reg:SI 26) (reg:SI 25)))
+ (clobber (match_dup 3))
+ (clobber (match_dup 4))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (match_dup 5))])
+ (set (match_operand:SI 0 "move_dest_operand" "") (reg:SI 29))]
+ ""
+ "
+{
+ operands[3] = gen_reg_rtx (SImode);
+
+ if (TARGET_64BIT)
+ {
+ operands[5] = gen_rtx_REG (SImode, 2);
+ operands[4] = operands[5];
+ }
+ else
+ {
+ operands[5] = gen_rtx_REG (SImode, 31);
+ operands[4] = gen_reg_rtx (SImode);
+ }
+ if (GET_CODE (operands[2]) == CONST_INT && pa_emit_hpdiv_const (operands, 1))
+ DONE;
+}")
+
+(define_insn ""
+ [(set (reg:SI 29)
+ (udiv:SI (reg:SI 26) (match_operand:SI 0 "div_operand" "")))
+ (clobber (match_operand:SI 1 "register_operand" "=a"))
+ (clobber (match_operand:SI 2 "register_operand" "=&r"))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (reg:SI 31))]
+ "!TARGET_64BIT"
+ "*
+ return pa_output_div_insn (operands, 1, insn);"
+ [(set_attr "type" "milli")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_millicode_call (insn)")))])
+
+(define_insn ""
+ [(set (reg:SI 29)
+ (udiv:SI (reg:SI 26) (match_operand:SI 0 "div_operand" "")))
+ (clobber (match_operand:SI 1 "register_operand" "=a"))
+ (clobber (match_operand:SI 2 "register_operand" "=&r"))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (reg:SI 2))]
+ "TARGET_64BIT"
+ "*
+ return pa_output_div_insn (operands, 1, insn);"
+ [(set_attr "type" "milli")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_millicode_call (insn)")))])
+
+(define_expand "modsi3"
+ [(set (reg:SI 26) (match_operand:SI 1 "move_src_operand" ""))
+ (set (reg:SI 25) (match_operand:SI 2 "move_src_operand" ""))
+ (parallel [(set (reg:SI 29) (mod:SI (reg:SI 26) (reg:SI 25)))
+ (clobber (match_dup 3))
+ (clobber (match_dup 4))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (match_dup 5))])
+ (set (match_operand:SI 0 "move_dest_operand" "") (reg:SI 29))]
+ ""
+ "
+{
+ if (TARGET_64BIT)
+ {
+ operands[5] = gen_rtx_REG (SImode, 2);
+ operands[4] = operands[5];
+ }
+ else
+ {
+ operands[5] = gen_rtx_REG (SImode, 31);
+ operands[4] = gen_reg_rtx (SImode);
+ }
+ operands[3] = gen_reg_rtx (SImode);
+}")
+
+(define_insn ""
+ [(set (reg:SI 29) (mod:SI (reg:SI 26) (reg:SI 25)))
+ (clobber (match_operand:SI 0 "register_operand" "=a"))
+ (clobber (match_operand:SI 1 "register_operand" "=&r"))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (reg:SI 31))]
+ "!TARGET_64BIT"
+ "*
+ return pa_output_mod_insn (0, insn);"
+ [(set_attr "type" "milli")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_millicode_call (insn)")))])
+
+(define_insn ""
+ [(set (reg:SI 29) (mod:SI (reg:SI 26) (reg:SI 25)))
+ (clobber (match_operand:SI 0 "register_operand" "=a"))
+ (clobber (match_operand:SI 1 "register_operand" "=&r"))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (reg:SI 2))]
+ "TARGET_64BIT"
+ "*
+ return pa_output_mod_insn (0, insn);"
+ [(set_attr "type" "milli")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_millicode_call (insn)")))])
+
+(define_expand "umodsi3"
+ [(set (reg:SI 26) (match_operand:SI 1 "move_src_operand" ""))
+ (set (reg:SI 25) (match_operand:SI 2 "move_src_operand" ""))
+ (parallel [(set (reg:SI 29) (umod:SI (reg:SI 26) (reg:SI 25)))
+ (clobber (match_dup 3))
+ (clobber (match_dup 4))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (match_dup 5))])
+ (set (match_operand:SI 0 "move_dest_operand" "") (reg:SI 29))]
+ ""
+ "
+{
+ if (TARGET_64BIT)
+ {
+ operands[5] = gen_rtx_REG (SImode, 2);
+ operands[4] = operands[5];
+ }
+ else
+ {
+ operands[5] = gen_rtx_REG (SImode, 31);
+ operands[4] = gen_reg_rtx (SImode);
+ }
+ operands[3] = gen_reg_rtx (SImode);
+}")
+
+(define_insn ""
+ [(set (reg:SI 29) (umod:SI (reg:SI 26) (reg:SI 25)))
+ (clobber (match_operand:SI 0 "register_operand" "=a"))
+ (clobber (match_operand:SI 1 "register_operand" "=&r"))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (reg:SI 31))]
+ "!TARGET_64BIT"
+ "*
+ return pa_output_mod_insn (1, insn);"
+ [(set_attr "type" "milli")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_millicode_call (insn)")))])
+
+(define_insn ""
+ [(set (reg:SI 29) (umod:SI (reg:SI 26) (reg:SI 25)))
+ (clobber (match_operand:SI 0 "register_operand" "=a"))
+ (clobber (match_operand:SI 1 "register_operand" "=&r"))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 25))
+ (clobber (reg:SI 2))]
+ "TARGET_64BIT"
+ "*
+ return pa_output_mod_insn (1, insn);"
+ [(set_attr "type" "milli")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_millicode_call (insn)")))])
+
+;;- and instructions
+;; We define DImode `and` so with DImode `not` we can get
+;; DImode `andn`. Other combinations are possible.
+
+(define_expand "anddi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (and:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "and_operand" "")))]
+ "TARGET_64BIT"
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (and:DI (match_operand:DI 1 "register_operand" "%?r,0")
+ (match_operand:DI 2 "and_operand" "rO,P")))]
+ "TARGET_64BIT"
+ "* return pa_output_64bit_and (operands); "
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+; The ? for op1 makes reload prefer zdepi instead of loading a huge
+; constant with ldil;ldo.
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%?r,0")
+ (match_operand:SI 2 "and_operand" "rO,P")))]
+ ""
+ "* return pa_output_and (operands); "
+ [(set_attr "type" "binary,shift")
+ (set_attr "length" "4,4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI (not:DI (match_operand:DI 1 "register_operand" "r"))
+ (match_operand:DI 2 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "andcm %2,%1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (and:SI (not:SI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r")))]
+ ""
+ "andcm %2,%1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+(define_expand "iordi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ior:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "reg_or_cint_ior_operand" "")))]
+ "TARGET_64BIT"
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (ior:DI (match_operand:DI 1 "register_operand" "0,0")
+ (match_operand:DI 2 "cint_ior_operand" "M,i")))]
+ "TARGET_64BIT"
+ "* return pa_output_64bit_ior (operands); "
+ [(set_attr "type" "binary,shift")
+ (set_attr "length" "4,4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ior:DI (match_operand:DI 1 "register_operand" "%r")
+ (match_operand:DI 2 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "or %1,%2,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+;; Need a define_expand because we've run out of CONST_OK... characters.
+(define_expand "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ior:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "reg_or_cint_ior_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "0,0")
+ (match_operand:SI 2 "cint_ior_operand" "M,i")))]
+ ""
+ "* return pa_output_ior (operands); "
+ [(set_attr "type" "binary,shift")
+ (set_attr "length" "4,4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%r")
+ (match_operand:SI 2 "register_operand" "r")))]
+ ""
+ "or %1,%2,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+(define_expand "xordi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (xor:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))]
+ "TARGET_64BIT"
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (xor:DI (match_operand:DI 1 "register_operand" "%r")
+ (match_operand:DI 2 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "xor %1,%2,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%r")
+ (match_operand:SI 2 "register_operand" "r")))]
+ ""
+ "xor %1,%2,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+(define_expand "negdi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (neg:DI (match_operand:DI 1 "register_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (neg:DI (match_operand:DI 1 "register_operand" "r")))]
+ "!TARGET_64BIT"
+ "sub %%r0,%R1,%R0\;{subb|sub,b} %%r0,%1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (neg:DI (match_operand:DI 1 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "sub %%r0,%1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "4")])
+
+(define_expand "negvdi2"
+ [(parallel [(set (match_operand:DI 0 "register_operand" "")
+ (neg:DI (match_operand:DI 1 "register_operand" "")))
+ (trap_if (ne (neg:TI (sign_extend:TI (match_dup 1)))
+ (sign_extend:TI (neg:DI (match_dup 1))))
+ (const_int 0))])]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (neg:DI (match_operand:DI 1 "register_operand" "r")))
+ (trap_if (ne (neg:TI (sign_extend:TI (match_dup 1)))
+ (sign_extend:TI (neg:DI (match_dup 1))))
+ (const_int 0))]
+ "!TARGET_64BIT"
+ "sub %%r0,%R1,%R0\;{subbo|sub,b,tsv} %%r0,%1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (neg:DI (match_operand:DI 1 "register_operand" "r")))
+ (trap_if (ne (neg:TI (sign_extend:TI (match_dup 1)))
+ (sign_extend:TI (neg:DI (match_dup 1))))
+ (const_int 0))]
+ "TARGET_64BIT"
+ "sub,tsv %%r0,%1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "4")])
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (match_operand:SI 1 "register_operand" "r")))]
+ ""
+ "sub %%r0,%1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "4")])
+
+(define_insn "negvsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (match_operand:SI 1 "register_operand" "r")))
+ (trap_if (ne (neg:DI (sign_extend:DI (match_dup 1)))
+ (sign_extend:DI (neg:SI (match_dup 1))))
+ (const_int 0))]
+ ""
+ "{subo|sub,tsv} %%r0,%1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "4")])
+
+(define_expand "one_cmpldi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (not:DI (match_operand:DI 1 "register_operand" "")))]
+ ""
+ "
+{
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (not:DI (match_operand:DI 1 "register_operand" "r")))]
+ "!TARGET_64BIT"
+ "uaddcm %%r0,%1,%0\;uaddcm %%r0,%R1,%R0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (not:DI (match_operand:DI 1 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "uaddcm %%r0,%1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "4")])
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (not:SI (match_operand:SI 1 "register_operand" "r")))]
+ ""
+ "uaddcm %%r0,%1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "4")])
+
+;; Floating point arithmetic instructions.
+
+(define_insn "adddf3"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (plus:DF (match_operand:DF 1 "register_operand" "f")
+ (match_operand:DF 2 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fadd,dbl %1,%2,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "pa_combine_type" "faddsub")
+ (set_attr "length" "4")])
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (plus:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fadd,sgl %1,%2,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "pa_combine_type" "faddsub")
+ (set_attr "length" "4")])
+
+(define_insn "subdf3"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (minus:DF (match_operand:DF 1 "register_operand" "f")
+ (match_operand:DF 2 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fsub,dbl %1,%2,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "pa_combine_type" "faddsub")
+ (set_attr "length" "4")])
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (minus:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fsub,sgl %1,%2,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "pa_combine_type" "faddsub")
+ (set_attr "length" "4")])
+
+(define_insn "muldf3"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (mult:DF (match_operand:DF 1 "register_operand" "f")
+ (match_operand:DF 2 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fmpy,dbl %1,%2,%0"
+ [(set_attr "type" "fpmuldbl")
+ (set_attr "pa_combine_type" "fmpy")
+ (set_attr "length" "4")])
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (mult:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fmpy,sgl %1,%2,%0"
+ [(set_attr "type" "fpmulsgl")
+ (set_attr "pa_combine_type" "fmpy")
+ (set_attr "length" "4")])
+
+(define_insn "divdf3"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (div:DF (match_operand:DF 1 "register_operand" "f")
+ (match_operand:DF 2 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fdiv,dbl %1,%2,%0"
+ [(set_attr "type" "fpdivdbl")
+ (set_attr "length" "4")])
+
+(define_insn "divsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (div:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fdiv,sgl %1,%2,%0"
+ [(set_attr "type" "fpdivsgl")
+ (set_attr "length" "4")])
+
+;; Processors prior to PA 2.0 don't have a fneg instruction. Fast
+;; negation can be done by subtracting from plus zero. However, this
+;; violates the IEEE standard when negating plus and minus zero.
+;; The slow path toggles the sign bit in the general registers.
+(define_expand "negdf2"
+ [(set (match_operand:DF 0 "register_operand" "")
+ (neg:DF (match_operand:DF 1 "register_operand" "")))]
+ "!TARGET_SOFT_FLOAT"
+{
+ if (TARGET_PA_20 || !flag_signed_zeros)
+ emit_insn (gen_negdf2_fast (operands[0], operands[1]));
+ else
+ emit_insn (gen_negdf2_slow (operands[0], operands[1]));
+ DONE;
+})
+
+(define_insn "negdf2_slow"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (neg:DF (match_operand:DF 1 "register_operand" "r")))]
+ "!TARGET_SOFT_FLOAT && !TARGET_PA_20"
+ "*
+{
+ if (rtx_equal_p (operands[0], operands[1]))
+ return \"and,< %1,%1,%0\;depi,tr 1,0,1,%0\;depi 0,0,1,%0\";
+ else
+ return \"and,< %1,%1,%0\;depi,tr 1,0,1,%0\;depi 0,0,1,%0\;copy %R1,%R0\";
+}"
+ [(set_attr "type" "multi")
+ (set (attr "length")
+ (if_then_else (match_test "rtx_equal_p (operands[0], operands[1])")
+ (const_int 12)
+ (const_int 16)))])
+
+(define_insn "negdf2_fast"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (neg:DF (match_operand:DF 1 "register_operand" "f")))]
+ "!TARGET_SOFT_FLOAT"
+ "*
+{
+ if (TARGET_PA_20)
+ return \"fneg,dbl %1,%0\";
+ else
+ return \"fsub,dbl %%fr0,%1,%0\";
+}"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_expand "negsf2"
+ [(set (match_operand:SF 0 "register_operand" "")
+ (neg:SF (match_operand:SF 1 "register_operand" "")))]
+ "!TARGET_SOFT_FLOAT"
+{
+ if (TARGET_PA_20 || !flag_signed_zeros)
+ emit_insn (gen_negsf2_fast (operands[0], operands[1]));
+ else
+ emit_insn (gen_negsf2_slow (operands[0], operands[1]));
+ DONE;
+})
+
+(define_insn "negsf2_slow"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (neg:SF (match_operand:SF 1 "register_operand" "r")))]
+ "!TARGET_SOFT_FLOAT && !TARGET_PA_20"
+ "and,< %1,%1,%0\;depi,tr 1,0,1,%0\;depi 0,0,1,%0"
+ [(set_attr "type" "multi")
+ (set_attr "length" "12")])
+
+(define_insn "negsf2_fast"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (neg:SF (match_operand:SF 1 "register_operand" "f")))]
+ "!TARGET_SOFT_FLOAT"
+ "*
+{
+ if (TARGET_PA_20)
+ return \"fneg,sgl %1,%0\";
+ else
+ return \"fsub,sgl %%fr0,%1,%0\";
+}"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "absdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (abs:DF (match_operand:DF 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fabs,dbl %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (abs:SF (match_operand:SF 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fabs,sgl %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn "sqrtdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (sqrt:DF (match_operand:DF 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fsqrt,dbl %1,%0"
+ [(set_attr "type" "fpsqrtdbl")
+ (set_attr "length" "4")])
+
+(define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (sqrt:SF (match_operand:SF 1 "register_operand" "f")))]
+ "! TARGET_SOFT_FLOAT"
+ "fsqrt,sgl %1,%0"
+ [(set_attr "type" "fpsqrtsgl")
+ (set_attr "length" "4")])
+
+;; PA 2.0 floating point instructions
+
+; fmpyfadd patterns
+(define_insn "fmadf4"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (fma:DF (match_operand:DF 1 "register_operand" "f")
+ (match_operand:DF 2 "register_operand" "f")
+ (match_operand:DF 3 "register_operand" "f")))]
+ "TARGET_PA_20 && ! TARGET_SOFT_FLOAT"
+ "fmpyfadd,dbl %1,%2,%3,%0"
+ [(set_attr "type" "fpmuldbl")
+ (set_attr "length" "4")])
+
+(define_insn "fmasf4"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (fma:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")
+ (match_operand:SF 3 "register_operand" "f")))]
+ "TARGET_PA_20 && ! TARGET_SOFT_FLOAT"
+ "fmpyfadd,sgl %1,%2,%3,%0"
+ [(set_attr "type" "fpmulsgl")
+ (set_attr "length" "4")])
+
+; fmpynfadd patterns
+(define_insn "fnmadf4"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (fma:DF (neg:DF (match_operand:DF 1 "register_operand" "f"))
+ (match_operand:DF 2 "register_operand" "f")
+ (match_operand:DF 3 "register_operand" "f")))]
+ "TARGET_PA_20 && ! TARGET_SOFT_FLOAT"
+ "fmpynfadd,dbl %1,%2,%3,%0"
+ [(set_attr "type" "fpmuldbl")
+ (set_attr "length" "4")])
+
+(define_insn "fnmasf4"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (fma:SF (neg:SF (match_operand:SF 1 "register_operand" "f"))
+ (match_operand:SF 2 "register_operand" "f")
+ (match_operand:SF 3 "register_operand" "f")))]
+ "TARGET_PA_20 && ! TARGET_SOFT_FLOAT"
+ "fmpynfadd,sgl %1,%2,%3,%0"
+ [(set_attr "type" "fpmulsgl")
+ (set_attr "length" "4")])
+
+; fnegabs patterns
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (neg:DF (abs:DF (match_operand:DF 1 "register_operand" "f"))))]
+ "TARGET_PA_20 && ! TARGET_SOFT_FLOAT"
+ "fnegabs,dbl %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (neg:SF (abs:SF (match_operand:SF 1 "register_operand" "f"))))]
+ "TARGET_PA_20 && ! TARGET_SOFT_FLOAT"
+ "fnegabs,sgl %1,%0"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (neg:DF (abs:DF (match_operand:DF 1 "register_operand" "f"))))
+ (set (match_operand:DF 2 "register_operand" "=&f") (abs:DF (match_dup 1)))]
+ "(! TARGET_SOFT_FLOAT && TARGET_PA_20
+ && ! reg_overlap_mentioned_p (operands[2], operands[1]))"
+ "#"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "8")])
+
+(define_split
+ [(set (match_operand:DF 0 "register_operand" "")
+ (neg:DF (abs:DF (match_operand:DF 1 "register_operand" ""))))
+ (set (match_operand:DF 2 "register_operand" "") (abs:DF (match_dup 1)))]
+ "! TARGET_SOFT_FLOAT && TARGET_PA_20"
+ [(set (match_dup 2) (abs:DF (match_dup 1)))
+ (set (match_dup 0) (neg:DF (abs:DF (match_dup 1))))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (neg:SF (abs:SF (match_operand:SF 1 "register_operand" "f"))))
+ (set (match_operand:SF 2 "register_operand" "=&f") (abs:SF (match_dup 1)))]
+ "(! TARGET_SOFT_FLOAT && TARGET_PA_20
+ && ! reg_overlap_mentioned_p (operands[2], operands[1]))"
+ "#"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "8")])
+
+(define_split
+ [(set (match_operand:SF 0 "register_operand" "")
+ (neg:SF (abs:SF (match_operand:SF 1 "register_operand" ""))))
+ (set (match_operand:SF 2 "register_operand" "") (abs:SF (match_dup 1)))]
+ "! TARGET_SOFT_FLOAT && TARGET_PA_20"
+ [(set (match_dup 2) (abs:SF (match_dup 1)))
+ (set (match_dup 0) (neg:SF (abs:SF (match_dup 1))))]
+ "")
+
+;; Negating a multiply can be faked by adding zero in a fused multiply-add
+;; instruction if we can ignore the sign of zero.
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (neg:DF (mult:DF (match_operand:DF 1 "register_operand" "f")
+ (match_operand:DF 2 "register_operand" "f"))))]
+ "!TARGET_SOFT_FLOAT && TARGET_PA_20 && !flag_signed_zeros"
+ "fmpynfadd,dbl %1,%2,%%fr0,%0"
+ [(set_attr "type" "fpmuldbl")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (neg:SF (mult:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f"))))]
+ "!TARGET_SOFT_FLOAT && TARGET_PA_20 && !flag_signed_zeros"
+ "fmpynfadd,sgl %1,%2,%%fr0,%0"
+ [(set_attr "type" "fpmuldbl")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (neg:DF (mult:DF (match_operand:DF 1 "register_operand" "f")
+ (match_operand:DF 2 "register_operand" "f"))))
+ (set (match_operand:DF 3 "register_operand" "=&f")
+ (mult:DF (match_dup 1) (match_dup 2)))]
+ "(!TARGET_SOFT_FLOAT && TARGET_PA_20 && !flag_signed_zeros
+ && ! (reg_overlap_mentioned_p (operands[3], operands[1])
+ || reg_overlap_mentioned_p (operands[3], operands[2])))"
+ "#"
+ [(set_attr "type" "fpmuldbl")
+ (set_attr "length" "8")])
+
+(define_split
+ [(set (match_operand:DF 0 "register_operand" "")
+ (neg:DF (mult:DF (match_operand:DF 1 "register_operand" "")
+ (match_operand:DF 2 "register_operand" ""))))
+ (set (match_operand:DF 3 "register_operand" "")
+ (mult:DF (match_dup 1) (match_dup 2)))]
+ "!TARGET_SOFT_FLOAT && TARGET_PA_20 && !flag_signed_zeros"
+ [(set (match_dup 3) (mult:DF (match_dup 1) (match_dup 2)))
+ (set (match_dup 0) (neg:DF (mult:DF (match_dup 1) (match_dup 2))))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (neg:SF (mult:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f"))))
+ (set (match_operand:SF 3 "register_operand" "=&f")
+ (mult:SF (match_dup 1) (match_dup 2)))]
+ "(!TARGET_SOFT_FLOAT && TARGET_PA_20 && !flag_signed_zeros
+ && ! (reg_overlap_mentioned_p (operands[3], operands[1])
+ || reg_overlap_mentioned_p (operands[3], operands[2])))"
+ "#"
+ [(set_attr "type" "fpmuldbl")
+ (set_attr "length" "8")])
+
+(define_split
+ [(set (match_operand:SF 0 "register_operand" "")
+ (neg:SF (mult:SF (match_operand:SF 1 "register_operand" "")
+ (match_operand:SF 2 "register_operand" ""))))
+ (set (match_operand:SF 3 "register_operand" "")
+ (mult:SF (match_dup 1) (match_dup 2)))]
+ "!TARGET_SOFT_FLOAT && TARGET_PA_20&& !flag_signed_zeros"
+ [(set (match_dup 3) (mult:SF (match_dup 1) (match_dup 2)))
+ (set (match_dup 0) (neg:SF (mult:SF (match_dup 1) (match_dup 2))))]
+ "")
+
+;;- Shift instructions
+
+;; Optimized special case of shifting.
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m")
+ (const_int 24)))]
+ ""
+ "ldb%M1 %1,%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lshiftrt:SI (match_operand:SI 1 "memory_operand" "m")
+ (const_int 16)))]
+ ""
+ "ldh%M1 %1,%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (mult:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "shadd_operand" ""))
+ (match_operand:SI 1 "register_operand" "r")))]
+ ""
+ "{sh%O3addl %2,%1,%0|shladd,l %2,%O3,%1,%0} "
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (mult:DI (match_operand:DI 2 "register_operand" "r")
+ (match_operand:DI 3 "shadd_operand" ""))
+ (match_operand:DI 1 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "shladd,l %2,%O3,%1,%0"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+(define_expand "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ashift:SI (match_operand:SI 1 "lhs_lshift_operand" "")
+ (match_operand:SI 2 "arith32_operand" "")))]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) != CONST_INT)
+ {
+ rtx temp = gen_reg_rtx (SImode);
+ emit_insn (gen_subsi3 (temp, GEN_INT (31), operands[2]));
+ if (GET_CODE (operands[1]) == CONST_INT)
+ emit_insn (gen_zvdep_imm32 (operands[0], operands[1], temp));
+ else
+ emit_insn (gen_zvdep32 (operands[0], operands[1], temp));
+ DONE;
+ }
+ /* Make sure both inputs are not constants,
+ there are no patterns for that. */
+ operands[1] = force_reg (SImode, operands[1]);
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "n")))]
+ ""
+ "{zdep|depw,z} %1,%P2,%L2,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+; Match cases of op1 a CONST_INT here that zvdep_imm32 doesn't handle.
+; Doing it like this makes slightly better code since reload can
+; replace a register with a known value in range -16..15 with a
+; constant. Ideally, we would like to merge zvdep32 and zvdep_imm32,
+; but since we have no more CONST_OK... characters, that is not
+; possible.
+(define_insn "zvdep32"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ashift:SI (match_operand:SI 1 "arith5_operand" "r,L")
+ (minus:SI (const_int 31)
+ (match_operand:SI 2 "register_operand" "q,q"))))]
+ ""
+ "@
+ {zvdep %1,32,%0|depw,z %1,%%sar,32,%0}
+ {zvdepi %1,32,%0|depwi,z %1,%%sar,32,%0}"
+ [(set_attr "type" "shift,shift")
+ (set_attr "length" "4,4")])
+
+(define_insn "zvdep_imm32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashift:SI (match_operand:SI 1 "lhs_lshift_cint_operand" "")
+ (minus:SI (const_int 31)
+ (match_operand:SI 2 "register_operand" "q"))))]
+ ""
+ "*
+{
+ unsigned HOST_WIDE_INT x = UINTVAL (operands[1]);
+ operands[2] = GEN_INT (4 + exact_log2 ((x >> 4) + 1));
+ operands[1] = GEN_INT ((x & 0xf) - 0x10);
+ return \"{zvdepi %1,%2,%0|depwi,z %1,%%sar,%2,%0}\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "vdepi_ior"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ior:SI (ashift:SI (match_operand:SI 1 "const_int_operand" "")
+ (minus:SI (const_int 31)
+ (match_operand:SI 2 "register_operand" "q")))
+ (match_operand:SI 3 "register_operand" "0")))]
+ ; accept ...0001...1, can this be generalized?
+ "exact_log2 (INTVAL (operands[1]) + 1) > 0"
+ "*
+{
+ HOST_WIDE_INT x = INTVAL (operands[1]);
+ operands[2] = GEN_INT (exact_log2 (x + 1));
+ return \"{vdepi -1,%2,%0|depwi -1,%%sar,%2,%0}\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "vdepi_and"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (and:SI (rotate:SI (match_operand:SI 1 "const_int_operand" "")
+ (minus:SI (const_int 31)
+ (match_operand:SI 2 "register_operand" "q")))
+ (match_operand:SI 3 "register_operand" "0")))]
+ ; this can be generalized...!
+ "INTVAL (operands[1]) == -2"
+ "*
+{
+ HOST_WIDE_INT x = INTVAL (operands[1]);
+ operands[2] = GEN_INT (exact_log2 ((~x) + 1));
+ return \"{vdepi 0,%2,%0|depwi 0,%%sar,%2,%0}\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_expand "ashldi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ashift:DI (match_operand:DI 1 "lhs_lshift_operand" "")
+ (match_operand:DI 2 "arith32_operand" "")))]
+ "TARGET_64BIT"
+ "
+{
+ if (GET_CODE (operands[2]) != CONST_INT)
+ {
+ rtx temp = gen_reg_rtx (DImode);
+ emit_insn (gen_subdi3 (temp, GEN_INT (63), operands[2]));
+ if (GET_CODE (operands[1]) == CONST_INT)
+ emit_insn (gen_zvdep_imm64 (operands[0], operands[1], temp));
+ else
+ emit_insn (gen_zvdep64 (operands[0], operands[1], temp));
+ DONE;
+ }
+ /* Make sure both inputs are not constants,
+ there are no patterns for that. */
+ operands[1] = force_reg (DImode, operands[1]);
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "const_int_operand" "n")))]
+ "TARGET_64BIT"
+ "depd,z %1,%p2,%Q2,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+; Match cases of op1 a CONST_INT here that zvdep_imm64 doesn't handle.
+; Doing it like this makes slightly better code since reload can
+; replace a register with a known value in range -16..15 with a
+; constant. Ideally, we would like to merge zvdep64 and zvdep_imm64,
+; but since we have no more CONST_OK... characters, that is not
+; possible.
+(define_insn "zvdep64"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (ashift:DI (match_operand:DI 1 "arith5_operand" "r,L")
+ (minus:DI (const_int 63)
+ (match_operand:DI 2 "register_operand" "q,q"))))]
+ "TARGET_64BIT"
+ "@
+ depd,z %1,%%sar,64,%0
+ depdi,z %1,%%sar,64,%0"
+ [(set_attr "type" "shift,shift")
+ (set_attr "length" "4,4")])
+
+(define_insn "zvdep_imm64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (match_operand:DI 1 "lhs_lshift_cint_operand" "")
+ (minus:DI (const_int 63)
+ (match_operand:DI 2 "register_operand" "q"))))]
+ "TARGET_64BIT"
+ "*
+{
+ unsigned HOST_WIDE_INT x = UINTVAL (operands[1]);
+ operands[2] = GEN_INT (4 + exact_log2 ((x >> 4) + 1));
+ operands[1] = GEN_INT ((x & 0x1f) - 0x20);
+ return \"depdi,z %1,%%sar,%2,%0\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ior:DI (ashift:DI (match_operand:DI 1 "const_int_operand" "")
+ (minus:DI (const_int 63)
+ (match_operand:DI 2 "register_operand" "q")))
+ (match_operand:DI 3 "register_operand" "0")))]
+ ; accept ...0001...1, can this be generalized?
+ "TARGET_64BIT && exact_log2 (INTVAL (operands[1]) + 1) > 0"
+ "*
+{
+ HOST_WIDE_INT x = INTVAL (operands[1]);
+ operands[2] = GEN_INT (exact_log2 (x + 1));
+ return \"depdi -1,%%sar,%2,%0\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI (rotate:DI (match_operand:DI 1 "const_int_operand" "")
+ (minus:DI (const_int 63)
+ (match_operand:DI 2 "register_operand" "q")))
+ (match_operand:DI 3 "register_operand" "0")))]
+ ; this can be generalized...!
+ "TARGET_64BIT && INTVAL (operands[1]) == -2"
+ "*
+{
+ HOST_WIDE_INT x = INTVAL (operands[1]);
+ operands[2] = GEN_INT (exact_log2 ((~x) + 1));
+ return \"depdi 0,%%sar,%2,%0\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_expand "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "arith32_operand" "")))]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) != CONST_INT)
+ {
+ rtx temp = gen_reg_rtx (SImode);
+ emit_insn (gen_subsi3 (temp, GEN_INT (31), operands[2]));
+ emit_insn (gen_vextrs32 (operands[0], operands[1], temp));
+ DONE;
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "n")))]
+ ""
+ "{extrs|extrw,s} %1,%P2,%L2,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "vextrs32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r")
+ (minus:SI (const_int 31)
+ (match_operand:SI 2 "register_operand" "q"))))]
+ ""
+ "{vextrs %1,32,%0|extrw,s %1,%%sar,32,%0}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_expand "ashrdi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "arith32_operand" "")))]
+ "TARGET_64BIT"
+ "
+{
+ if (GET_CODE (operands[2]) != CONST_INT)
+ {
+ rtx temp = gen_reg_rtx (DImode);
+ emit_insn (gen_subdi3 (temp, GEN_INT (63), operands[2]));
+ emit_insn (gen_vextrs64 (operands[0], operands[1], temp));
+ DONE;
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashiftrt:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "const_int_operand" "n")))]
+ "TARGET_64BIT"
+ "extrd,s %1,%p2,%Q2,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "vextrs64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashiftrt:DI (match_operand:DI 1 "register_operand" "r")
+ (minus:DI (const_int 63)
+ (match_operand:DI 2 "register_operand" "q"))))]
+ "TARGET_64BIT"
+ "extrd,s %1,%%sar,64,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "shift5_operand" "q,n")))]
+ ""
+ "@
+ {vshd %%r0,%1,%0|shrpw %%r0,%1,%%sar,%0}
+ {extru|extrw,u} %1,%P2,%L2,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "lshrdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (lshiftrt:DI (match_operand:DI 1 "register_operand" "r,r")
+ (match_operand:DI 2 "shift6_operand" "q,n")))]
+ "TARGET_64BIT"
+ "@
+ shrpd %%r0,%1,%%sar,%0
+ extrd,u %1,%p2,%Q2,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+; Shift right pair word 0 to 31 bits.
+(define_insn "shrpsi4"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "r,r")
+ (minus:SI (const_int 32)
+ (match_operand:SI 3 "shift5_operand" "q,n")))
+ (lshiftrt:SI (match_operand:SI 2 "register_operand" "r,r")
+ (match_dup 3))))]
+ ""
+ "@
+ {vshd %1,%2,%0|shrpw %1,%2,%%sar,%0}
+ {shd|shrpw} %1,%2,%3,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+; Shift right pair doubleword 0 to 63 bits.
+(define_insn "shrpdi4"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (ior:DI (ashift:DI (match_operand:SI 1 "register_operand" "r,r")
+ (minus:DI (const_int 64)
+ (match_operand:DI 3 "shift6_operand" "q,n")))
+ (lshiftrt:DI (match_operand:DI 2 "register_operand" "r,r")
+ (match_dup 3))))]
+ "TARGET_64BIT"
+ "@
+ shrpd %1,%2,%%sar,%0
+ shrpd %1,%2,%3,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn "rotrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "shift5_operand" "q,n")))]
+ ""
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 31);
+ return \"{shd|shrpw} %1,%1,%2,%0\";
+ }
+ else
+ return \"{vshd %1,%1,%0|shrpw %1,%1,%%sar,%0}\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_expand "rotlsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (rotate:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "arith32_operand" "")))]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) != CONST_INT)
+ {
+ rtx temp = gen_reg_rtx (SImode);
+ emit_insn (gen_subsi3 (temp, GEN_INT (32), operands[2]));
+ emit_insn (gen_rotrsi3 (operands[0], operands[1], temp));
+ DONE;
+ }
+ /* Else expand normally. */
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (rotate:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "n")))]
+ ""
+ "*
+{
+ operands[2] = GEN_INT ((32 - INTVAL (operands[2])) & 31);
+ return \"{shd|shrpw} %1,%1,%2,%0\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 5 "plus_xor_ior_operator"
+ [(ashift:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 3 "const_int_operand" "n"))
+ (lshiftrt:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "n"))]))]
+ "INTVAL (operands[3]) + INTVAL (operands[4]) == 32"
+ "{shd|shrpw} %1,%2,%4,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 5 "plus_xor_ior_operator"
+ [(lshiftrt:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "n"))
+ (ashift:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 3 "const_int_operand" "n"))]))]
+ "INTVAL (operands[3]) + INTVAL (operands[4]) == 32"
+ "{shd|shrpw} %1,%2,%4,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" ""))
+ (match_operand:SI 3 "const_int_operand" "")))]
+ "exact_log2 (1 + (INTVAL (operands[3]) >> (INTVAL (operands[2]) & 31))) > 0"
+ "*
+{
+ int cnt = INTVAL (operands[2]) & 31;
+ operands[3] = GEN_INT (exact_log2 (1 + (INTVAL (operands[3]) >> cnt)));
+ operands[2] = GEN_INT (31 - cnt);
+ return \"{zdep|depw,z} %1,%2,%3,%0\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+;; Unconditional and other jump instructions.
+
+;; Trivial return used when no epilogue is needed.
+(define_insn "return"
+ [(return)
+ (use (reg:SI 2))]
+ "pa_can_use_return_insn ()"
+ "*
+{
+ if (TARGET_PA_20)
+ return \"bve%* (%%r2)\";
+ return \"bv%* %%r0(%%r2)\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+;; This is used for most returns.
+(define_insn "return_internal"
+ [(return)
+ (use (reg:SI 2))]
+ ""
+ "*
+{
+ if (TARGET_PA_20)
+ return \"bve%* (%%r2)\";
+ return \"bv%* %%r0(%%r2)\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+;; This is used for eh returns which bypass the return stub.
+(define_insn "return_external_pic"
+ [(return)
+ (clobber (reg:SI 1))
+ (use (reg:SI 2))]
+ "!TARGET_NO_SPACE_REGS
+ && !TARGET_PA_20
+ && flag_pic && crtl->calls_eh_return"
+ "ldsid (%%sr0,%%r2),%%r1\;mtsp %%r1,%%sr0\;be%* 0(%%sr0,%%r2)"
+ [(set_attr "type" "branch")
+ (set_attr "length" "12")])
+
+(define_expand "prologue"
+ [(const_int 0)]
+ ""
+ "pa_expand_prologue ();DONE;")
+
+(define_expand "sibcall_epilogue"
+ [(return)]
+ ""
+ "
+{
+ pa_expand_epilogue ();
+ DONE;
+}")
+
+(define_expand "epilogue"
+ [(return)]
+ ""
+ "
+{
+ rtx x;
+
+ /* Try to use the trivial return first. Else use the full epilogue. */
+ if (pa_can_use_return_insn ())
+ x = gen_return ();
+ else
+ {
+ pa_expand_epilogue ();
+
+ /* EH returns bypass the normal return stub. Thus, we must do an
+ interspace branch to return from functions that call eh_return.
+ This is only a problem for returns from shared code on ports
+ using space registers. */
+ if (!TARGET_NO_SPACE_REGS
+ && !TARGET_PA_20
+ && flag_pic && crtl->calls_eh_return)
+ x = gen_return_external_pic ();
+ else
+ x = gen_return_internal ();
+ }
+ emit_jump_insn (x);
+ DONE;
+}")
+
+; Used by hppa_profile_hook to load the starting address of the current
+; function; operand 1 contains the address of the label in operand 3
+(define_insn "load_offset_label_address"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (minus:SI (match_operand:SI 2 "" "")
+ (label_ref:SI (match_operand 3 "" "")))))]
+ ""
+ "ldo %2-%l3(%1),%0"
+ [(set_attr "type" "multi")
+ (set_attr "length" "4")])
+
+; Output a code label and load its address.
+(define_insn "lcla1"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (label_ref:SI (match_operand 1 "" "")))
+ (const_int 0)]
+ "!TARGET_PA_20"
+ "*
+{
+ output_asm_insn (\"bl .+8,%0\;depi 0,31,2,%0\", operands);
+ (*targetm.asm_out.internal_label) (asm_out_file, \"L\",
+ CODE_LABEL_NUMBER (operands[1]));
+ return \"\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+(define_insn "lcla2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (label_ref:SI (match_operand 1 "" "")))
+ (const_int 0)]
+ "TARGET_PA_20"
+ "*
+{
+ (*targetm.asm_out.internal_label) (asm_out_file, \"L\",
+ CODE_LABEL_NUMBER (operands[1]));
+ return \"mfia %0\";
+}"
+ [(set_attr "type" "move")
+ (set_attr "length" "4")])
+
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 2)] UNSPECV_BLOCKAGE)]
+ ""
+ ""
+ [(set_attr "length" "0")])
+
+(define_insn "jump"
+ [(set (pc) (label_ref (match_operand 0 "" "")))]
+ ""
+ "*
+{
+ /* An unconditional branch which can reach its target. */
+ if (get_attr_length (insn) < 16)
+ return \"b%* %l0\";
+
+ return pa_output_lbranch (operands[0], insn, 1);
+}"
+ [(set_attr "type" "uncond_branch")
+ (set_attr "pa_combine_type" "uncond_branch")
+ (set (attr "length")
+ (cond [(match_test "pa_jump_in_call_delay (insn)")
+ (if_then_else (lt (abs (minus (match_dup 0)
+ (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (const_int 8))
+ (lt (abs (minus (match_dup 0) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 4)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 20)
+ (not (match_test "flag_pic"))
+ (const_int 16)]
+ (const_int 24)))])
+
+;;; Hope this is only within a function...
+(define_insn "indirect_jump"
+ [(set (pc) (match_operand 0 "register_operand" "r"))]
+ "GET_MODE (operands[0]) == word_mode"
+ "bv%* %%r0(%0)"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+;;; An indirect jump can be optimized to a direct jump. GAS for the
+;;; SOM target doesn't allow branching to a label inside a function.
+;;; We also don't correctly compute branch distances for labels
+;;; outside the current function. Thus, we use an indirect jump can't
+;;; be optimized to a direct jump for all targets. We assume that
+;;; the branch target is in the same space (i.e., nested function
+;;; jumping to a label in an outer function in the same translation
+;;; unit).
+(define_expand "nonlocal_goto"
+ [(use (match_operand 0 "general_operand" ""))
+ (use (match_operand 1 "general_operand" ""))
+ (use (match_operand 2 "general_operand" ""))
+ (use (match_operand 3 "general_operand" ""))]
+ ""
+{
+ rtx lab = operands[1];
+ rtx stack = operands[2];
+ rtx fp = operands[3];
+
+ lab = copy_to_reg (lab);
+
+ emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
+ emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
+
+ /* Restore the frame pointer. The virtual_stack_vars_rtx is saved
+ instead of the hard_frame_pointer_rtx in the save area. As a
+ result, an extra instruction is needed to adjust for the offset
+ of the virtual stack variables and the hard frame pointer. */
+ if (GET_CODE (fp) != REG)
+ fp = force_reg (Pmode, fp);
+ emit_move_insn (hard_frame_pointer_rtx, plus_constant (Pmode, fp, -8));
+
+ emit_stack_restore (SAVE_NONLOCAL, stack);
+
+ emit_use (hard_frame_pointer_rtx);
+ emit_use (stack_pointer_rtx);
+
+ /* Nonlocal goto jumps are only used between functions in the same
+ translation unit. Thus, we can avoid the extra overhead of an
+ interspace jump. */
+ emit_jump_insn (gen_indirect_goto (lab));
+ emit_barrier ();
+ DONE;
+})
+
+(define_insn "indirect_goto"
+ [(unspec [(match_operand 0 "register_operand" "=r")] UNSPEC_GOTO)]
+ "GET_MODE (operands[0]) == word_mode"
+ "bv%* %%r0(%0)"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+;; Subroutines of "casesi".
+;; operand 0 is index
+;; operand 1 is the minimum bound
+;; operand 2 is the maximum bound - minimum bound + 1
+;; operand 3 is CODE_LABEL for the table;
+;; operand 4 is the CODE_LABEL to go to if index out of range.
+
+(define_expand "casesi"
+ [(match_operand:SI 0 "general_operand" "")
+ (match_operand:SI 1 "const_int_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")
+ (match_operand 3 "" "")
+ (match_operand 4 "" "")]
+ ""
+ "
+{
+ if (GET_CODE (operands[0]) != REG)
+ operands[0] = force_reg (SImode, operands[0]);
+
+ if (operands[1] != const0_rtx)
+ {
+ rtx index = gen_reg_rtx (SImode);
+
+ operands[1] = gen_int_mode (-INTVAL (operands[1]), SImode);
+ if (!INT_14_BITS (operands[1]))
+ operands[1] = force_reg (SImode, operands[1]);
+ emit_insn (gen_addsi3 (index, operands[0], operands[1]));
+ operands[0] = index;
+ }
+
+ if (!INT_5_BITS (operands[2]))
+ operands[2] = force_reg (SImode, operands[2]);
+
+ /* This branch prevents us finding an insn for the delay slot of the
+ following vectored branch. It might be possible to use the delay
+ slot if an index value of -1 was used to transfer to the out-of-range
+ label. In order to do this, we would have to output the -1 vector
+ element after the delay insn. The casesi output code would have to
+ check if the casesi insn is in a delay branch sequence and output
+ the delay insn if one is found. If this was done, then it might
+ then be worthwhile to split the casesi patterns to improve scheduling.
+ However, it's not clear that all this extra complexity is worth
+ the effort. */
+ {
+ rtx test = gen_rtx_GTU (VOIDmode, operands[0], operands[2]);
+ emit_jump_insn (gen_cbranchsi4 (test, operands[0], operands[2], operands[4]));
+ }
+
+ /* In 64bit mode we must make sure to wipe the upper bits of the register
+ just in case the addition overflowed or we had random bits in the
+ high part of the register. */
+ if (TARGET_64BIT)
+ {
+ rtx index = gen_reg_rtx (DImode);
+
+ emit_insn (gen_extendsidi2 (index, operands[0]));
+ operands[0] = index;
+ }
+
+ if (TARGET_64BIT)
+ emit_jump_insn (gen_casesi64p (operands[0], operands[3]));
+ else if (flag_pic)
+ emit_jump_insn (gen_casesi32p (operands[0], operands[3]));
+ else
+ emit_jump_insn (gen_casesi32 (operands[0], operands[3]));
+ DONE;
+}")
+
+;;; 32-bit code, absolute branch table.
+(define_insn "casesi32"
+ [(set (pc) (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"))]
+ "!flag_pic"
+ "ldil L'%l1,%2\;ldo R'%l1(%2),%2\;{ldwx|ldw},s %0(%2),%2\;bv,n %%r0(%2)"
+ [(set_attr "type" "multi")
+ (set_attr "length" "16")])
+
+;;; 32-bit code, relative branch table.
+(define_insn "casesi32p"
+ [(set (pc) (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"))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ "flag_pic"
+ "{bl .+8,%2\;depi 0,31,2,%2|mfia %2}\;ldo {%l1-.|%l1+4-.}(%2),%2\;\
+{ldwx|ldw},s %0(%2),%3\;{addl|add,l} %2,%3,%3\;bv,n %%r0(%3)"
+ [(set_attr "type" "multi")
+ (set (attr "length")
+ (if_then_else (match_test "TARGET_PA_20")
+ (const_int 20)
+ (const_int 24)))])
+
+;;; 64-bit code, 32-bit relative branch table.
+(define_insn "casesi64p"
+ [(set (pc) (mem:DI (plus:DI
+ (mult:DI (match_operand:DI 0 "register_operand" "r")
+ (const_int 8))
+ (label_ref (match_operand 1 "" "")))))
+ (clobber (match_scratch:DI 2 "=&r"))
+ (clobber (match_scratch:DI 3 "=&r"))]
+ ""
+ "mfia %2\;ldo %l1+4-.(%2),%2\;ldw,s %0(%2),%3\;extrd,s %3,63,32,%3\;\
+add,l %2,%3,%3\;bv,n %%r0(%3)"
+ [(set_attr "type" "multi")
+ (set_attr "length" "24")])
+
+
+;; Call patterns.
+;;- jump to subroutine
+
+(define_expand "call"
+ [(parallel [(call (match_operand:SI 0 "" "")
+ (match_operand 1 "" ""))
+ (clobber (reg:SI 2))])]
+ ""
+ "
+{
+ rtx op;
+ rtx nb = operands[1];
+
+ if (TARGET_PORTABLE_RUNTIME)
+ op = force_reg (SImode, XEXP (operands[0], 0));
+ else
+ {
+ op = XEXP (operands[0], 0);
+
+ /* Generate indirect long calls to non-local functions. */
+ if (!TARGET_64BIT && TARGET_LONG_CALLS && GET_CODE (op) == SYMBOL_REF)
+ {
+ tree call_decl = SYMBOL_REF_DECL (op);
+ if (!(call_decl && targetm.binds_local_p (call_decl)))
+ op = force_reg (word_mode, op);
+ }
+ }
+
+ if (TARGET_64BIT)
+ {
+ if (!virtuals_instantiated)
+ emit_move_insn (arg_pointer_rtx,
+ gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
+ GEN_INT (64)));
+ else
+ {
+ /* The loop pass can generate new libcalls after the virtual
+ registers are instantiated when fpregs are disabled because
+ the only method that we have for doing DImode multiplication
+ is with a libcall. This could be trouble if we haven't
+ allocated enough space for the outgoing arguments. */
+ gcc_assert (INTVAL (nb) <= crtl->outgoing_args_size);
+
+ emit_move_insn (arg_pointer_rtx,
+ gen_rtx_PLUS (word_mode, stack_pointer_rtx,
+ GEN_INT (STACK_POINTER_OFFSET + 64)));
+ }
+ }
+
+ /* Use two different patterns for calls to explicitly named functions
+ and calls through function pointers. This is necessary as these two
+ types of calls use different calling conventions, and CSE might try
+ to change the named call into an indirect call in some cases (using
+ two patterns keeps CSE from performing this optimization).
+
+ We now use even more call patterns as there was a subtle bug in
+ attempting to restore the pic register after a call using a simple
+ move insn. During reload, a instruction involving a pseudo register
+ with no explicit dependence on the PIC register can be converted
+ to an equivalent load from memory using the PIC register. If we
+ emit a simple move to restore the PIC register in the initial rtl
+ generation, then it can potentially be repositioned during scheduling.
+ and an instruction that eventually uses the PIC register may end up
+ between the call and the PIC register restore.
+
+ This only worked because there is a post call group of instructions
+ that are scheduled with the call. These instructions are included
+ in the same basic block as the call. However, calls can throw in
+ C++ code and a basic block has to terminate at the call if the call
+ can throw. This results in the PIC register restore being scheduled
+ independently from the call. So, we now hide the save and restore
+ of the PIC register in the call pattern until after reload. Then,
+ we split the moves out. A small side benefit is that we now don't
+ need to have a use of the PIC register in the return pattern and
+ the final save/restore operation is not needed.
+
+ I elected to just use register %r4 in the PIC patterns instead
+ of trying to force hppa_pic_save_rtx () to a callee saved register.
+ This might have required a new register class and constraint. It
+ was also simpler to just handle the restore from a register than a
+ generic pseudo. */
+ if (TARGET_64BIT)
+ {
+ rtx r4 = gen_rtx_REG (word_mode, 4);
+ if (GET_CODE (op) == SYMBOL_REF)
+ emit_call_insn (gen_call_symref_64bit (op, nb, r4));
+ else
+ {
+ op = force_reg (word_mode, op);
+ emit_call_insn (gen_call_reg_64bit (op, nb, r4));
+ }
+ }
+ else
+ {
+ if (GET_CODE (op) == SYMBOL_REF)
+ {
+ if (flag_pic)
+ {
+ rtx r4 = gen_rtx_REG (word_mode, 4);
+ emit_call_insn (gen_call_symref_pic (op, nb, r4));
+ }
+ else
+ emit_call_insn (gen_call_symref (op, nb));
+ }
+ else
+ {
+ rtx tmpreg = gen_rtx_REG (word_mode, 22);
+ emit_move_insn (tmpreg, force_reg (word_mode, op));
+ if (flag_pic)
+ {
+ rtx r4 = gen_rtx_REG (word_mode, 4);
+ emit_call_insn (gen_call_reg_pic (nb, r4));
+ }
+ else
+ emit_call_insn (gen_call_reg (nb));
+ }
+ }
+
+ DONE;
+}")
+
+;; We use function calls to set the attribute length of calls and millicode
+;; calls. This is necessary because of the large variety of call sequences.
+;; Implementing the calculation in rtl is difficult as well as ugly. As
+;; we need the same calculation in several places, maintenance becomes a
+;; nightmare.
+;;
+;; However, this has a subtle impact on branch shortening. When the
+;; expression used to set the length attribute of an instruction depends
+;; on a relative address (e.g., pc or a branch address), genattrtab
+;; notes that the insn's length is variable, and attempts to determine a
+;; worst-case default length and code to compute an insn's current length.
+
+;; The use of a function call hides the variable dependence of our calls
+;; and millicode calls. The result is genattrtab doesn't treat the operation
+;; as variable and it only generates code for the default case using our
+;; function call. Because of this, calls and millicode calls have a fixed
+;; length in the branch shortening pass, and some branches will use a longer
+;; code sequence than necessary. However, the length of any given call
+;; will still reflect its final code location and it may be shorter than
+;; the initial length estimate.
+
+;; It's possible to trick genattrtab by adding an expression involving `pc'
+;; in the set. However, when genattrtab hits a function call in its attempt
+;; to compute the default length, it marks the result as unknown and sets
+;; the default result to MAX_INT ;-( One possible fix that would allow
+;; calls to participate in branch shortening would be to make the call to
+;; insn_default_length a target option. Then, we could massage unknown
+;; results. Another fix might be to change genattrtab so that it just does
+;; the call in the variable case as it already does for the fixed case.
+
+(define_insn "call_symref"
+ [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" "i"))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (const_int 0))]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[0], 0);
+}"
+ [(set_attr "type" "call")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 0)")))])
+
+(define_insn "call_symref_pic"
+ [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" "i"))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 2))
+ (use (reg:SI 19))
+ (use (const_int 0))]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "#")
+
+;; Split out the PIC register save and restore after reload. As the
+;; split is done after reload, there are some situations in which we
+;; unnecessarily save and restore %r4. This happens when there is a
+;; single call and the PIC register is not used after the call.
+;;
+;; The split has to be done since call_from_call_insn () can't handle
+;; the pattern as is. Noreturn calls are special because they have to
+;; terminate the basic block. The split has to contain more than one
+;; insn.
+(define_split
+ [(parallel [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 2))
+ (use (reg:SI 19))
+ (use (const_int 0))])]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT && reload_completed
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ [(set (match_dup 2) (reg:SI 19))
+ (parallel [(call (mem:SI (match_dup 0))
+ (match_dup 1))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 0))])]
+ "")
+
+(define_split
+ [(parallel [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 2))
+ (use (reg:SI 19))
+ (use (const_int 0))])]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT && reload_completed"
+ [(set (match_dup 2) (reg:SI 19))
+ (parallel [(call (mem:SI (match_dup 0))
+ (match_dup 1))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 0))])
+ (set (reg:SI 19) (match_dup 2))]
+ "")
+
+(define_insn "*call_symref_pic_post_reload"
+ [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" "i"))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 0))]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[0], 0);
+}"
+ [(set_attr "type" "call")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 0)")))])
+
+;; This pattern is split if it is necessary to save and restore the
+;; PIC register.
+(define_insn "call_symref_64bit"
+ [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" "i"))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))]
+ "TARGET_64BIT"
+ "#")
+
+;; Split out the PIC register save and restore after reload. As the
+;; split is done after reload, there are some situations in which we
+;; unnecessarily save and restore %r4. This happens when there is a
+;; single call and the PIC register is not used after the call.
+;;
+;; The split has to be done since call_from_call_insn () can't handle
+;; the pattern as is. Noreturn calls are special because they have to
+;; terminate the basic block. The split has to contain more than one
+;; insn.
+(define_split
+ [(parallel [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" ""))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))])]
+ "TARGET_64BIT && reload_completed
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ [(set (match_dup 2) (reg:DI 27))
+ (parallel [(call (mem:SI (match_dup 0))
+ (match_dup 1))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))])]
+ "")
+
+(define_split
+ [(parallel [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" ""))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))])]
+ "TARGET_64BIT && reload_completed"
+ [(set (match_dup 2) (reg:DI 27))
+ (parallel [(call (mem:SI (match_dup 0))
+ (match_dup 1))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))])
+ (set (reg:DI 27) (match_dup 2))]
+ "")
+
+(define_insn "*call_symref_64bit_post_reload"
+ [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" "i"))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))]
+ "TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[0], 0);
+}"
+ [(set_attr "type" "call")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 0)")))])
+
+(define_insn "call_reg"
+ [(call (mem:SI (reg:SI 22))
+ (match_operand 0 "" "i"))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (const_int 1))]
+ "!TARGET_64BIT"
+ "*
+{
+ return pa_output_indirect_call (insn, gen_rtx_REG (word_mode, 22));
+}"
+ [(set_attr "type" "dyncall")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_indirect_call (insn)")))])
+
+;; This pattern is split if it is necessary to save and restore the
+;; PIC register.
+(define_insn "call_reg_pic"
+ [(call (mem:SI (reg:SI 22))
+ (match_operand 0 "" "i"))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 1))
+ (use (reg:SI 19))
+ (use (const_int 1))]
+ "!TARGET_64BIT"
+ "#")
+
+;; Split out the PIC register save and restore after reload. As the
+;; split is done after reload, there are some situations in which we
+;; unnecessarily save and restore %r4. This happens when there is a
+;; single call and the PIC register is not used after the call.
+;;
+;; The split has to be done since call_from_call_insn () can't handle
+;; the pattern as is. Noreturn calls are special because they have to
+;; terminate the basic block. The split has to contain more than one
+;; insn.
+(define_split
+ [(parallel [(call (mem:SI (reg:SI 22))
+ (match_operand 0 "" ""))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 1))
+ (use (reg:SI 19))
+ (use (const_int 1))])]
+ "!TARGET_64BIT && reload_completed
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ [(set (match_dup 1) (reg:SI 19))
+ (parallel [(call (mem:SI (reg:SI 22))
+ (match_dup 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 1))])]
+ "")
+
+(define_split
+ [(parallel [(call (mem:SI (reg:SI 22))
+ (match_operand 0 "" ""))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 1))
+ (use (reg:SI 19))
+ (use (const_int 1))])]
+ "!TARGET_64BIT && reload_completed"
+ [(set (match_dup 1) (reg:SI 19))
+ (parallel [(call (mem:SI (reg:SI 22))
+ (match_dup 0))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 1))])
+ (set (reg:SI 19) (match_dup 1))]
+ "")
+
+(define_insn "*call_reg_pic_post_reload"
+ [(call (mem:SI (reg:SI 22))
+ (match_operand 0 "" "i"))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 1))]
+ "!TARGET_64BIT"
+ "*
+{
+ return pa_output_indirect_call (insn, gen_rtx_REG (word_mode, 22));
+}"
+ [(set_attr "type" "dyncall")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_indirect_call (insn)")))])
+
+;; This pattern is split if it is necessary to save and restore the
+;; PIC register.
+(define_insn "call_reg_64bit"
+ [(call (mem:SI (match_operand:DI 0 "register_operand" "r"))
+ (match_operand 1 "" "i"))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))]
+ "TARGET_64BIT"
+ "#")
+
+;; Split out the PIC register save and restore after reload. As the
+;; split is done after reload, there are some situations in which we
+;; unnecessarily save and restore %r4. This happens when there is a
+;; single call and the PIC register is not used after the call.
+;;
+;; The split has to be done since call_from_call_insn () can't handle
+;; the pattern as is. Noreturn calls are special because they have to
+;; terminate the basic block. The split has to contain more than one
+;; insn.
+(define_split
+ [(parallel [(call (mem:SI (match_operand 0 "register_operand" ""))
+ (match_operand 1 "" ""))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])]
+ "TARGET_64BIT && reload_completed
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ [(set (match_dup 2) (reg:DI 27))
+ (parallel [(call (mem:SI (match_dup 0))
+ (match_dup 1))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])]
+ "")
+
+(define_split
+ [(parallel [(call (mem:SI (match_operand 0 "register_operand" ""))
+ (match_operand 1 "" ""))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])]
+ "TARGET_64BIT && reload_completed"
+ [(set (match_dup 2) (reg:DI 27))
+ (parallel [(call (mem:SI (match_dup 0))
+ (match_dup 1))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])
+ (set (reg:DI 27) (match_dup 2))]
+ "")
+
+(define_insn "*call_reg_64bit_post_reload"
+ [(call (mem:SI (match_operand:DI 0 "register_operand" "r"))
+ (match_operand 1 "" "i"))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_indirect_call (insn, operands[0]);
+}"
+ [(set_attr "type" "dyncall")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 12)]
+ (symbol_ref "pa_attr_length_indirect_call (insn)")))])
+
+(define_expand "call_value"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (match_operand:SI 1 "" "")
+ (match_operand 2 "" "")))
+ (clobber (reg:SI 2))])]
+ ""
+{
+ rtx op;
+ rtx dst = operands[0];
+ rtx nb = operands[2];
+ bool call_powf = false;
+
+ if (TARGET_PORTABLE_RUNTIME)
+ op = force_reg (SImode, XEXP (operands[1], 0));
+ else
+ {
+ op = XEXP (operands[1], 0);
+ if (GET_CODE (op) == SYMBOL_REF)
+ {
+ /* Handle special call to buggy powf function. */
+ if (TARGET_HPUX && !TARGET_DISABLE_FPREGS && !TARGET_SOFT_FLOAT
+ && !strcmp (targetm.strip_name_encoding (XSTR (op, 0)), "powf"))
+ call_powf = true;
+
+ /* Generate indirect long calls to non-local functions. */
+ else if (!TARGET_64BIT && TARGET_LONG_CALLS)
+ {
+ tree call_decl = SYMBOL_REF_DECL (op);
+ if (!(call_decl && targetm.binds_local_p (call_decl)))
+ op = force_reg (word_mode, op);
+ }
+ }
+ }
+
+ if (TARGET_64BIT)
+ {
+ if (!virtuals_instantiated)
+ emit_move_insn (arg_pointer_rtx,
+ gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
+ GEN_INT (64)));
+ else
+ {
+ /* The loop pass can generate new libcalls after the virtual
+ registers are instantiated when fpregs are disabled because
+ the only method that we have for doing DImode multiplication
+ is with a libcall. This could be trouble if we haven't
+ allocated enough space for the outgoing arguments. */
+ gcc_assert (INTVAL (nb) <= crtl->outgoing_args_size);
+
+ emit_move_insn (arg_pointer_rtx,
+ gen_rtx_PLUS (word_mode, stack_pointer_rtx,
+ GEN_INT (STACK_POINTER_OFFSET + 64)));
+ }
+ }
+
+ /* Use two different patterns for calls to explicitly named functions
+ and calls through function pointers. This is necessary as these two
+ types of calls use different calling conventions, and CSE might try
+ to change the named call into an indirect call in some cases (using
+ two patterns keeps CSE from performing this optimization).
+
+ We now use even more call patterns as there was a subtle bug in
+ attempting to restore the pic register after a call using a simple
+ move insn. During reload, a instruction involving a pseudo register
+ with no explicit dependence on the PIC register can be converted
+ to an equivalent load from memory using the PIC register. If we
+ emit a simple move to restore the PIC register in the initial rtl
+ generation, then it can potentially be repositioned during scheduling.
+ and an instruction that eventually uses the PIC register may end up
+ between the call and the PIC register restore.
+
+ This only worked because there is a post call group of instructions
+ that are scheduled with the call. These instructions are included
+ in the same basic block as the call. However, calls can throw in
+ C++ code and a basic block has to terminate at the call if the call
+ can throw. This results in the PIC register restore being scheduled
+ independently from the call. So, we now hide the save and restore
+ of the PIC register in the call pattern until after reload. Then,
+ we split the moves out. A small side benefit is that we now don't
+ need to have a use of the PIC register in the return pattern and
+ the final save/restore operation is not needed.
+
+ I elected to just use register %r4 in the PIC patterns instead
+ of trying to force hppa_pic_save_rtx () to a callee saved register.
+ This might have required a new register class and constraint. It
+ was also simpler to just handle the restore from a register than a
+ generic pseudo. */
+ if (TARGET_64BIT)
+ {
+ rtx r4 = gen_rtx_REG (word_mode, 4);
+ if (GET_CODE (op) == SYMBOL_REF)
+ {
+ if (call_powf)
+ emit_call_insn (gen_call_val_powf_64bit (dst, op, nb, r4));
+ else
+ emit_call_insn (gen_call_val_symref_64bit (dst, op, nb, r4));
+ }
+ else
+ {
+ op = force_reg (word_mode, op);
+ emit_call_insn (gen_call_val_reg_64bit (dst, op, nb, r4));
+ }
+ }
+ else
+ {
+ if (GET_CODE (op) == SYMBOL_REF)
+ {
+ if (flag_pic)
+ {
+ rtx r4 = gen_rtx_REG (word_mode, 4);
+
+ if (call_powf)
+ emit_call_insn (gen_call_val_powf_pic (dst, op, nb, r4));
+ else
+ emit_call_insn (gen_call_val_symref_pic (dst, op, nb, r4));
+ }
+ else
+ {
+ if (call_powf)
+ emit_call_insn (gen_call_val_powf (dst, op, nb));
+ else
+ emit_call_insn (gen_call_val_symref (dst, op, nb));
+ }
+ }
+ else
+ {
+ rtx tmpreg = gen_rtx_REG (word_mode, 22);
+ emit_move_insn (tmpreg, force_reg (word_mode, op));
+ if (flag_pic)
+ {
+ rtx r4 = gen_rtx_REG (word_mode, 4);
+ emit_call_insn (gen_call_val_reg_pic (dst, nb, r4));
+ }
+ else
+ emit_call_insn (gen_call_val_reg (dst, nb));
+ }
+ }
+
+ DONE;
+})
+
+(define_insn "call_val_symref"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (const_int 0))]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[1], 0);
+}"
+ [(set_attr "type" "call")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 0)")))])
+
+;; powf function clobbers %fr12
+(define_insn "call_val_powf"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (reg:DF 48))
+ (use (const_int 1))]
+ "TARGET_HPUX && !TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[1], 0);
+}"
+ [(set_attr "type" "call")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 0)")))])
+
+(define_insn "call_val_symref_pic"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 3))
+ (use (reg:SI 19))
+ (use (const_int 0))]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "#")
+
+;; Split out the PIC register save and restore after reload. As the
+;; split is done after reload, there are some situations in which we
+;; unnecessarily save and restore %r4. This happens when there is a
+;; single call and the PIC register is not used after the call.
+;;
+;; The split has to be done since call_from_call_insn () can't handle
+;; the pattern as is. Noreturn calls are special because they have to
+;; terminate the basic block. The split has to contain more than one
+;; insn.
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 3))
+ (use (reg:SI 19))
+ (use (const_int 0))])]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT && reload_completed
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ [(set (match_dup 3) (reg:SI 19))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 0))])]
+ "")
+
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 3))
+ (use (reg:SI 19))
+ (use (const_int 0))])]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT && reload_completed"
+ [(set (match_dup 3) (reg:SI 19))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 0))])
+ (set (reg:SI 19) (match_dup 3))]
+ "")
+
+(define_insn "*call_val_symref_pic_post_reload"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 0))]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[1], 0);
+}"
+ [(set_attr "type" "call")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 0)")))])
+
+;; powf function clobbers %fr12
+(define_insn "call_val_powf_pic"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (reg:DF 48))
+ (clobber (match_operand 3))
+ (use (reg:SI 19))
+ (use (const_int 1))]
+ "TARGET_HPUX && !TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "#")
+
+;; Split out the PIC register save and restore after reload. As the
+;; split is done after reload, there are some situations in which we
+;; unnecessarily save and restore %r4. This happens when there is a
+;; single call and the PIC register is not used after the call.
+;;
+;; The split has to be done since call_from_call_insn () can't handle
+;; the pattern as is. Noreturn calls are special because they have to
+;; terminate the basic block. The split has to contain more than one
+;; insn.
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (reg:DF 48))
+ (clobber (match_operand 3))
+ (use (reg:SI 19))
+ (use (const_int 1))])]
+ "TARGET_HPUX && !TARGET_PORTABLE_RUNTIME && !TARGET_64BIT && reload_completed
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ [(set (match_dup 3) (reg:SI 19))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (reg:DF 48))
+ (use (reg:SI 19))
+ (use (const_int 1))])]
+ "")
+
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (reg:DF 48))
+ (clobber (match_operand 3))
+ (use (reg:SI 19))
+ (use (const_int 1))])]
+ "TARGET_HPUX && !TARGET_PORTABLE_RUNTIME && !TARGET_64BIT && reload_completed"
+ [(set (match_dup 3) (reg:SI 19))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (reg:DF 48))
+ (use (reg:SI 19))
+ (use (const_int 1))])
+ (set (reg:SI 19) (match_dup 3))]
+ "")
+
+(define_insn "*call_val_powf_pic_post_reload"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (reg:DF 48))
+ (use (reg:SI 19))
+ (use (const_int 1))]
+ "TARGET_HPUX && !TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[1], 0);
+}"
+ [(set_attr "type" "call")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 0)")))])
+
+;; This pattern is split if it is necessary to save and restore the
+;; PIC register.
+(define_insn "call_val_symref_64bit"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 3))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))]
+ "TARGET_64BIT"
+ "#")
+
+;; Split out the PIC register save and restore after reload. As the
+;; split is done after reload, there are some situations in which we
+;; unnecessarily save and restore %r4. This happens when there is a
+;; single call and the PIC register is not used after the call.
+;;
+;; The split has to be done since call_from_call_insn () can't handle
+;; the pattern as is. Noreturn calls are special because they have to
+;; terminate the basic block. The split has to contain more than one
+;; insn.
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 3))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))])]
+ "TARGET_64BIT && reload_completed
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ [(set (match_dup 3) (reg:DI 27))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))])]
+ "")
+
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 3))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))])]
+ "TARGET_64BIT && reload_completed"
+ [(set (match_dup 3) (reg:DI 27))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))])
+ (set (reg:DI 27) (match_dup 3))]
+ "")
+
+(define_insn "*call_val_symref_64bit_post_reload"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 0))]
+ "TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[1], 0);
+}"
+ [(set_attr "type" "call")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 0)")))])
+
+;; powf function clobbers %fr12
+(define_insn "call_val_powf_64bit"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (reg:DF 40))
+ (clobber (match_operand 3))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))]
+ "TARGET_64BIT && TARGET_HPUX"
+ "#")
+
+;; Split out the PIC register save and restore after reload. As the
+;; split is done after reload, there are some situations in which we
+;; unnecessarily save and restore %r4. This happens when there is a
+;; single call and the PIC register is not used after the call.
+;;
+;; The split has to be done since call_from_call_insn () can't handle
+;; the pattern as is. Noreturn calls are special because they have to
+;; terminate the basic block. The split has to contain more than one
+;; insn.
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (reg:DF 40))
+ (clobber (match_operand 3))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])]
+ "TARGET_64BIT && TARGET_HPUX && reload_completed
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ [(set (match_dup 3) (reg:DI 27))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (reg:DF 40))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])]
+ "")
+
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (reg:DF 40))
+ (clobber (match_operand 3))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])]
+ "TARGET_64BIT && TARGET_HPUX && reload_completed"
+ [(set (match_dup 3) (reg:DI 27))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (reg:DF 40))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])
+ (set (reg:DI 27) (match_dup 3))]
+ "")
+
+(define_insn "*call_val_powf_64bit_post_reload"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (reg:DF 40))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))]
+ "TARGET_64BIT && TARGET_HPUX"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[1], 0);
+}"
+ [(set_attr "type" "call")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 0)")))])
+
+(define_insn "call_val_reg"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (reg:SI 22))
+ (match_operand 1 "" "i")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (const_int 1))]
+ "!TARGET_64BIT"
+ "*
+{
+ return pa_output_indirect_call (insn, gen_rtx_REG (word_mode, 22));
+}"
+ [(set_attr "type" "dyncall")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_indirect_call (insn)")))])
+
+;; This pattern is split if it is necessary to save and restore the
+;; PIC register.
+(define_insn "call_val_reg_pic"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (reg:SI 22))
+ (match_operand 1 "" "i")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 2))
+ (use (reg:SI 19))
+ (use (const_int 1))]
+ "!TARGET_64BIT"
+ "#")
+
+;; Split out the PIC register save and restore after reload. As the
+;; split is done after reload, there are some situations in which we
+;; unnecessarily save and restore %r4. This happens when there is a
+;; single call and the PIC register is not used after the call.
+;;
+;; The split has to be done since call_from_call_insn () can't handle
+;; the pattern as is. Noreturn calls are special because they have to
+;; terminate the basic block. The split has to contain more than one
+;; insn.
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (reg:SI 22))
+ (match_operand 1 "" "")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 2))
+ (use (reg:SI 19))
+ (use (const_int 1))])]
+ "!TARGET_64BIT && reload_completed
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ [(set (match_dup 2) (reg:SI 19))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (reg:SI 22))
+ (match_dup 1)))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 1))])]
+ "")
+
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (reg:SI 22))
+ (match_operand 1 "" "")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (clobber (match_operand 2))
+ (use (reg:SI 19))
+ (use (const_int 1))])]
+ "!TARGET_64BIT && reload_completed"
+ [(set (match_dup 2) (reg:SI 19))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (reg:SI 22))
+ (match_dup 1)))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 1))])
+ (set (reg:SI 19) (match_dup 2))]
+ "")
+
+(define_insn "*call_val_reg_pic_post_reload"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (reg:SI 22))
+ (match_operand 1 "" "i")))
+ (clobber (reg:SI 1))
+ (clobber (reg:SI 2))
+ (use (reg:SI 19))
+ (use (const_int 1))]
+ "!TARGET_64BIT"
+ "*
+{
+ return pa_output_indirect_call (insn, gen_rtx_REG (word_mode, 22));
+}"
+ [(set_attr "type" "dyncall")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_indirect_call (insn)")))])
+
+;; This pattern is split if it is necessary to save and restore the
+;; PIC register.
+(define_insn "call_val_reg_64bit"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:DI 1 "register_operand" "r"))
+ (match_operand 2 "" "i")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 3))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))]
+ "TARGET_64BIT"
+ "#")
+
+;; Split out the PIC register save and restore after reload. As the
+;; split is done after reload, there are some situations in which we
+;; unnecessarily save and restore %r4. This happens when there is a
+;; single call and the PIC register is not used after the call.
+;;
+;; The split has to be done since call_from_call_insn () can't handle
+;; the pattern as is. Noreturn calls are special because they have to
+;; terminate the basic block. The split has to contain more than one
+;; insn.
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:DI 1 "register_operand" ""))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 3))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])]
+ "TARGET_64BIT && reload_completed
+ && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
+ [(set (match_dup 3) (reg:DI 27))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])]
+ "")
+
+(define_split
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:DI 1 "register_operand" ""))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (clobber (match_operand 3))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])]
+ "TARGET_64BIT && reload_completed"
+ [(set (match_dup 3) (reg:DI 27))
+ (parallel [(set (match_dup 0)
+ (call (mem:SI (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))])
+ (set (reg:DI 27) (match_dup 3))]
+ "")
+
+(define_insn "*call_val_reg_64bit_post_reload"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:DI 1 "register_operand" "r"))
+ (match_operand 2 "" "i")))
+ (clobber (reg:DI 1))
+ (clobber (reg:DI 2))
+ (use (reg:DI 27))
+ (use (reg:DI 29))
+ (use (const_int 1))]
+ "TARGET_64BIT"
+ "*
+{
+ return pa_output_indirect_call (insn, operands[1]);
+}"
+ [(set_attr "type" "dyncall")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 12)]
+ (symbol_ref "pa_attr_length_indirect_call (insn)")))])
+
+;; 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;
+
+ emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, 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;
+}")
+
+(define_expand "sibcall"
+ [(call (match_operand:SI 0 "" "")
+ (match_operand 1 "" ""))]
+ "!TARGET_PORTABLE_RUNTIME"
+ "
+{
+ rtx op, call_insn;
+ rtx nb = operands[1];
+
+ op = XEXP (operands[0], 0);
+
+ if (TARGET_64BIT)
+ {
+ if (!virtuals_instantiated)
+ emit_move_insn (arg_pointer_rtx,
+ gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
+ GEN_INT (64)));
+ else
+ {
+ /* The loop pass can generate new libcalls after the virtual
+ registers are instantiated when fpregs are disabled because
+ the only method that we have for doing DImode multiplication
+ is with a libcall. This could be trouble if we haven't
+ allocated enough space for the outgoing arguments. */
+ gcc_assert (INTVAL (nb) <= crtl->outgoing_args_size);
+
+ emit_move_insn (arg_pointer_rtx,
+ gen_rtx_PLUS (word_mode, stack_pointer_rtx,
+ GEN_INT (STACK_POINTER_OFFSET + 64)));
+ }
+ }
+
+ /* Indirect sibling calls are not allowed. */
+ if (TARGET_64BIT)
+ call_insn = gen_sibcall_internal_symref_64bit (op, operands[1]);
+ else
+ call_insn = gen_sibcall_internal_symref (op, operands[1]);
+
+ call_insn = emit_call_insn (call_insn);
+
+ if (TARGET_64BIT)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
+
+ /* We don't have to restore the PIC register. */
+ if (flag_pic)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
+
+ DONE;
+}")
+
+(define_insn "sibcall_internal_symref"
+ [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" "i"))
+ (clobber (reg:SI 1))
+ (use (reg:SI 2))
+ (use (const_int 0))]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[0], 1);
+}"
+ [(set_attr "type" "sibcall")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 1)")))])
+
+(define_insn "sibcall_internal_symref_64bit"
+ [(call (mem:SI (match_operand 0 "call_operand_address" ""))
+ (match_operand 1 "" "i"))
+ (clobber (reg:DI 1))
+ (use (reg:DI 2))
+ (use (const_int 0))]
+ "TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[0], 1);
+}"
+ [(set_attr "type" "sibcall")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 1)")))])
+
+(define_expand "sibcall_value"
+ [(set (match_operand 0 "" "")
+ (call (match_operand:SI 1 "" "")
+ (match_operand 2 "" "")))]
+ "!TARGET_PORTABLE_RUNTIME"
+ "
+{
+ rtx op, call_insn;
+ rtx nb = operands[1];
+
+ op = XEXP (operands[1], 0);
+
+ if (TARGET_64BIT)
+ {
+ if (!virtuals_instantiated)
+ emit_move_insn (arg_pointer_rtx,
+ gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
+ GEN_INT (64)));
+ else
+ {
+ /* The loop pass can generate new libcalls after the virtual
+ registers are instantiated when fpregs are disabled because
+ the only method that we have for doing DImode multiplication
+ is with a libcall. This could be trouble if we haven't
+ allocated enough space for the outgoing arguments. */
+ gcc_assert (INTVAL (nb) <= crtl->outgoing_args_size);
+
+ emit_move_insn (arg_pointer_rtx,
+ gen_rtx_PLUS (word_mode, stack_pointer_rtx,
+ GEN_INT (STACK_POINTER_OFFSET + 64)));
+ }
+ }
+
+ /* Indirect sibling calls are not allowed. */
+ if (TARGET_64BIT)
+ call_insn
+ = gen_sibcall_value_internal_symref_64bit (operands[0], op, operands[2]);
+ else
+ call_insn
+ = gen_sibcall_value_internal_symref (operands[0], op, operands[2]);
+
+ call_insn = emit_call_insn (call_insn);
+
+ if (TARGET_64BIT)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
+
+ /* We don't have to restore the PIC register. */
+ if (flag_pic)
+ use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
+
+ DONE;
+}")
+
+(define_insn "sibcall_value_internal_symref"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:SI 1))
+ (use (reg:SI 2))
+ (use (const_int 0))]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[1], 1);
+}"
+ [(set_attr "type" "sibcall")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 1)")))])
+
+(define_insn "sibcall_value_internal_symref_64bit"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "call_operand_address" ""))
+ (match_operand 2 "" "i")))
+ (clobber (reg:DI 1))
+ (use (reg:DI 2))
+ (use (const_int 0))]
+ "TARGET_64BIT"
+ "*
+{
+ pa_output_arg_descriptor (insn);
+ return pa_output_call (insn, operands[1], 1);
+}"
+ [(set_attr "type" "sibcall")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 8)]
+ (symbol_ref "pa_attr_length_call (insn, 1)")))])
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop"
+ [(set_attr "type" "move")
+ (set_attr "length" "4")])
+
+;; These are just placeholders so we know where branch tables
+;; begin and end.
+(define_insn "begin_brtab"
+ [(const_int 1)]
+ ""
+ "*
+{
+ /* Only GAS actually supports this pseudo-op. */
+ if (TARGET_GAS)
+ return \".begin_brtab\";
+ else
+ return \"\";
+}"
+ [(set_attr "type" "move")
+ (set_attr "length" "0")])
+
+(define_insn "end_brtab"
+ [(const_int 2)]
+ ""
+ "*
+{
+ /* Only GAS actually supports this pseudo-op. */
+ if (TARGET_GAS)
+ return \".end_brtab\";
+ else
+ return \"\";
+}"
+ [(set_attr "type" "move")
+ (set_attr "length" "0")])
+
+;;; EH does longjmp's from and within the data section. Thus,
+;;; an interspace branch is required for the longjmp implementation.
+;;; Registers r1 and r2 are used as scratch registers for the jump
+;;; when necessary.
+(define_expand "interspace_jump"
+ [(parallel
+ [(set (pc) (match_operand 0 "pmode_register_operand" "a"))
+ (clobber (match_dup 1))])]
+ ""
+ "
+{
+ operands[1] = gen_rtx_REG (word_mode, 2);
+}")
+
+(define_insn ""
+ [(set (pc) (match_operand 0 "pmode_register_operand" "a"))
+ (clobber (reg:SI 2))]
+ "TARGET_PA_20 && !TARGET_64BIT"
+ "bve%* (%0)"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (pc) (match_operand 0 "pmode_register_operand" "a"))
+ (clobber (reg:SI 2))]
+ "TARGET_NO_SPACE_REGS && !TARGET_64BIT"
+ "be%* 0(%%sr4,%0)"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (pc) (match_operand 0 "pmode_register_operand" "a"))
+ (clobber (reg:SI 2))]
+ "!TARGET_64BIT"
+ "ldsid (%%sr0,%0),%%r2\;mtsp %%r2,%%sr0\;be%* 0(%%sr0,%0)"
+ [(set_attr "type" "branch")
+ (set_attr "length" "12")])
+
+(define_insn ""
+ [(set (pc) (match_operand 0 "pmode_register_operand" "a"))
+ (clobber (reg:DI 2))]
+ "TARGET_64BIT"
+ "bve%* (%0)"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+(define_expand "builtin_longjmp"
+ [(unspec_volatile [(match_operand 0 "register_operand" "r")] UNSPECV_LONGJMP)]
+ ""
+ "
+{
+ /* The elements of the buffer are, in order: */
+ rtx fp = gen_rtx_MEM (Pmode, operands[0]);
+ rtx lab = gen_rtx_MEM (Pmode, plus_constant (Pmode, operands[0],
+ POINTER_SIZE / BITS_PER_UNIT));
+ rtx stack = gen_rtx_MEM (Pmode, plus_constant (Pmode, operands[0],
+ (POINTER_SIZE * 2) / BITS_PER_UNIT));
+ rtx pv = gen_rtx_REG (Pmode, 1);
+
+ emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
+ emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
+
+ /* Restore the frame pointer. The virtual_stack_vars_rtx is saved
+ instead of the hard_frame_pointer_rtx in the save area. We need
+ to adjust for the offset between these two values. */
+ if (GET_CODE (fp) != REG)
+ fp = force_reg (Pmode, fp);
+ emit_move_insn (hard_frame_pointer_rtx, plus_constant (Pmode, fp, -8));
+
+ /* This bit is the same as expand_builtin_longjmp. */
+ emit_stack_restore (SAVE_NONLOCAL, stack);
+ emit_use (hard_frame_pointer_rtx);
+ emit_use (stack_pointer_rtx);
+
+ /* Load the label we are jumping through into r1 so that we know
+ where to look for it when we get back to setjmp's function for
+ restoring the gp. */
+ emit_move_insn (pv, lab);
+
+ /* Prevent the insns above from being scheduled into the delay slot
+ of the interspace jump because the space register could change. */
+ emit_insn (gen_blockage ());
+
+ emit_jump_insn (gen_interspace_jump (pv));
+ emit_barrier ();
+ DONE;
+}")
+
+;;; Operands 2 and 3 are assumed to be CONST_INTs.
+(define_expand "extzvsi"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extract:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "uint5_operand" "")
+ (match_operand:SI 3 "uint5_operand" "")))]
+ ""
+ "
+{
+ unsigned HOST_WIDE_INT len = UINTVAL (operands[2]);
+ unsigned HOST_WIDE_INT pos = UINTVAL (operands[3]);
+
+ /* PA extraction insns don't support zero length bitfields or fields
+ extending beyond the left or right-most bits. Also, the predicate
+ rejects lengths equal to a word as they are better handled by
+ the move patterns. */
+ if (len == 0 || pos + len > 32)
+ FAIL;
+
+ /* From mips.md: extract_bit_field doesn't verify that our source
+ matches the predicate, so check it again here. */
+ if (!register_operand (operands[1], VOIDmode))
+ FAIL;
+
+ emit_insn (gen_extzv_32 (operands[0], operands[1],
+ operands[2], operands[3]));
+ DONE;
+}")
+
+(define_insn "extzv_32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "uint5_operand" "")
+ (match_operand:SI 3 "uint5_operand" "")))]
+ "UINTVAL (operands[2]) > 0
+ && UINTVAL (operands[2]) + UINTVAL (operands[3]) <= 32"
+ "{extru|extrw,u} %1,%3+%2-1,%2,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 2 "register_operand" "q")))]
+ ""
+ "{vextru %1,1,%0|extrw,u %1,%%sar,1,%0}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_expand "extzvdi"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extract:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "uint6_operand" "")
+ (match_operand:DI 3 "uint6_operand" "")))]
+ "TARGET_64BIT"
+ "
+{
+ unsigned HOST_WIDE_INT len = UINTVAL (operands[2]);
+ unsigned HOST_WIDE_INT pos = UINTVAL (operands[3]);
+
+ /* PA extraction insns don't support zero length bitfields or fields
+ extending beyond the left or right-most bits. Also, the predicate
+ rejects lengths equal to a doubleword as they are better handled by
+ the move patterns. */
+ if (len == 0 || pos + len > 64)
+ FAIL;
+
+ /* From mips.md: extract_bit_field doesn't verify that our source
+ matches the predicate, so check it again here. */
+ if (!register_operand (operands[1], VOIDmode))
+ FAIL;
+
+ emit_insn (gen_extzv_64 (operands[0], operands[1],
+ operands[2], operands[3]));
+ DONE;
+}")
+
+(define_insn "extzv_64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extract:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "uint6_operand" "")
+ (match_operand:DI 3 "uint6_operand" "")))]
+ "TARGET_64BIT
+ && UINTVAL (operands[2]) > 0
+ && UINTVAL (operands[2]) + UINTVAL (operands[3]) <= 64"
+ "extrd,u %1,%3+%2-1,%2,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extract:DI (match_operand:DI 1 "register_operand" "r")
+ (const_int 1)
+ (match_operand:DI 2 "register_operand" "q")))]
+ "TARGET_64BIT"
+ "extrd,u %1,%%sar,1,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+;;; Operands 2 and 3 are assumed to be CONST_INTs.
+(define_expand "extvsi"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extract:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "uint5_operand" "")
+ (match_operand:SI 3 "uint5_operand" "")))]
+ ""
+ "
+{
+ unsigned HOST_WIDE_INT len = UINTVAL (operands[2]);
+ unsigned HOST_WIDE_INT pos = UINTVAL (operands[3]);
+
+ /* PA extraction insns don't support zero length bitfields or fields
+ extending beyond the left or right-most bits. Also, the predicate
+ rejects lengths equal to a word as they are better handled by
+ the move patterns. */
+ if (len == 0 || pos + len > 32)
+ FAIL;
+
+ /* From mips.md: extract_bit_field doesn't verify that our source
+ matches the predicate, so check it again here. */
+ if (!register_operand (operands[1], VOIDmode))
+ FAIL;
+
+ emit_insn (gen_extv_32 (operands[0], operands[1],
+ operands[2], operands[3]));
+ DONE;
+}")
+
+(define_insn "extv_32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extract:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "uint5_operand" "")
+ (match_operand:SI 3 "uint5_operand" "")))]
+ "UINTVAL (operands[2]) > 0
+ && UINTVAL (operands[2]) + UINTVAL (operands[3]) <= 32"
+ "{extrs|extrw,s} %1,%3+%2-1,%2,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extract:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 2 "register_operand" "q")))]
+ "!TARGET_64BIT"
+ "{vextrs %1,1,%0|extrw,s %1,%%sar,1,%0}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_expand "extvdi"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (sign_extract:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "uint6_operand" "")
+ (match_operand:DI 3 "uint6_operand" "")))]
+ "TARGET_64BIT"
+ "
+{
+ unsigned HOST_WIDE_INT len = UINTVAL (operands[2]);
+ unsigned HOST_WIDE_INT pos = UINTVAL (operands[3]);
+
+ /* PA extraction insns don't support zero length bitfields or fields
+ extending beyond the left or right-most bits. Also, the predicate
+ rejects lengths equal to a doubleword as they are better handled by
+ the move patterns. */
+ if (len == 0 || pos + len > 64)
+ FAIL;
+
+ /* From mips.md: extract_bit_field doesn't verify that our source
+ matches the predicate, so check it again here. */
+ if (!register_operand (operands[1], VOIDmode))
+ FAIL;
+
+ emit_insn (gen_extv_64 (operands[0], operands[1],
+ operands[2], operands[3]));
+ DONE;
+}")
+
+(define_insn "extv_64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extract:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "uint6_operand" "")
+ (match_operand:DI 3 "uint6_operand" "")))]
+ "TARGET_64BIT
+ && UINTVAL (operands[2]) > 0
+ && UINTVAL (operands[2]) + UINTVAL (operands[3]) <= 64"
+ "extrd,s %1,%3+%2-1,%2,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extract:DI (match_operand:DI 1 "register_operand" "r")
+ (const_int 1)
+ (match_operand:DI 2 "register_operand" "q")))]
+ "TARGET_64BIT"
+ "extrd,s %1,%%sar,1,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+;;; Operands 1 and 2 are assumed to be CONST_INTs.
+(define_expand "insvsi"
+ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "uint5_operand" "")
+ (match_operand:SI 2 "uint5_operand" ""))
+ (match_operand:SI 3 "arith5_operand" ""))]
+ ""
+ "
+{
+ unsigned HOST_WIDE_INT len = UINTVAL (operands[1]);
+ unsigned HOST_WIDE_INT pos = UINTVAL (operands[2]);
+
+ /* PA insertion insns don't support zero length bitfields or fields
+ extending beyond the left or right-most bits. Also, the predicate
+ rejects lengths equal to a word as they are better handled by
+ the move patterns. */
+ if (len <= 0 || pos + len > 32)
+ FAIL;
+
+ /* From mips.md: insert_bit_field doesn't verify that our destination
+ matches the predicate, so check it again here. */
+ if (!register_operand (operands[0], VOIDmode))
+ FAIL;
+
+ emit_insn (gen_insv_32 (operands[0], operands[1],
+ operands[2], operands[3]));
+ DONE;
+}")
+
+(define_insn "insv_32"
+ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r,r")
+ (match_operand:SI 1 "uint5_operand" "")
+ (match_operand:SI 2 "uint5_operand" ""))
+ (match_operand:SI 3 "arith5_operand" "r,L"))]
+ "UINTVAL (operands[1]) > 0
+ && UINTVAL (operands[1]) + UINTVAL (operands[2]) <= 32"
+ "@
+ {dep|depw} %3,%2+%1-1,%1,%0
+ {depi|depwi} %3,%2+%1-1,%1,%0"
+ [(set_attr "type" "shift,shift")
+ (set_attr "length" "4,4")])
+
+;; Optimize insertion of const_int values of type 1...1xxxx.
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
+ (match_operand:SI 1 "uint5_operand" "")
+ (match_operand:SI 2 "uint5_operand" ""))
+ (match_operand:SI 3 "const_int_operand" ""))]
+ "(INTVAL (operands[3]) & 0x10) != 0 &&
+ (~INTVAL (operands[3]) & ((1L << INTVAL (operands[1])) - 1) & ~0xf) == 0"
+ "*
+{
+ operands[3] = GEN_INT ((INTVAL (operands[3]) & 0xf) - 0x10);
+ return \"{depi|depwi} %3,%2+%1-1,%1,%0\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_expand "insvdi"
+ [(set (zero_extract:DI (match_operand:DI 0 "register_operand" "")
+ (match_operand:DI 1 "uint6_operand" "")
+ (match_operand:DI 2 "uint6_operand" ""))
+ (match_operand:DI 3 "arith5_operand" ""))]
+ "TARGET_64BIT"
+ "
+{
+ unsigned HOST_WIDE_INT len = UINTVAL (operands[1]);
+ unsigned HOST_WIDE_INT pos = UINTVAL (operands[2]);
+
+ /* PA insertion insns don't support zero length bitfields or fields
+ extending beyond the left or right-most bits. Also, the predicate
+ rejects lengths equal to a doubleword as they are better handled by
+ the move patterns. */
+ if (len <= 0 || pos + len > 64)
+ FAIL;
+
+ /* From mips.md: insert_bit_field doesn't verify that our destination
+ matches the predicate, so check it again here. */
+ if (!register_operand (operands[0], VOIDmode))
+ FAIL;
+
+ emit_insn (gen_insv_64 (operands[0], operands[1],
+ operands[2], operands[3]));
+ DONE;
+}")
+
+(define_insn "insv_64"
+ [(set (zero_extract:DI (match_operand:DI 0 "register_operand" "+r,r")
+ (match_operand:DI 1 "uint6_operand" "")
+ (match_operand:DI 2 "uint6_operand" ""))
+ (match_operand:DI 3 "arith5_operand" "r,L"))]
+ "TARGET_64BIT
+ && UINTVAL (operands[1]) > 0
+ && UINTVAL (operands[1]) + UINTVAL (operands[2]) <= 64"
+ "@
+ depd %3,%2+%1-1,%1,%0
+ depdi %3,%2+%1-1,%1,%0"
+ [(set_attr "type" "shift,shift")
+ (set_attr "length" "4,4")])
+
+;; Optimize insertion of const_int values of type 1...1xxxx.
+(define_insn ""
+ [(set (zero_extract:DI (match_operand:DI 0 "register_operand" "+r")
+ (match_operand:DI 1 "uint6_operand" "")
+ (match_operand:DI 2 "uint6_operand" ""))
+ (match_operand:DI 3 "const_int_operand" ""))]
+ "(INTVAL (operands[3]) & 0x10) != 0
+ && TARGET_64BIT
+ && (~INTVAL (operands[3]) & ((1L << INTVAL (operands[1])) - 1) & ~0xf) == 0"
+ "*
+{
+ operands[3] = GEN_INT ((INTVAL (operands[3]) & 0xf) - 0x10);
+ return \"depdi %3,%2+%1-1,%1,%0\";
+}"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (const_int 32)))]
+ "TARGET_64BIT"
+ "depd,z %1,31,32,%0"
+ [(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
+;; This insn is used for some loop tests, typically loops reversed when
+;; strength reduction is used. It is actually created when the instruction
+;; combination phase combines the special loop test. Since this insn
+;; is both a jump insn and has an output, it must deal with its own
+;; reloads, hence the `m' constraints. The `!' constraints direct reload
+;; to not choose the register alternatives in the event a reload is needed.
+(define_insn "decrement_and_branch_until_zero"
+ [(set (pc)
+ (if_then_else
+ (match_operator 2 "comparison_operator"
+ [(plus:SI
+ (match_operand:SI 0 "reg_before_reload_operand" "+!r,!*f,*m")
+ (match_operand:SI 1 "int5_operand" "L,L,L"))
+ (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0) (match_dup 1)))
+ (clobber (match_scratch:SI 4 "=X,r,r"))]
+ ""
+ "* return pa_output_dbra (operands, insn, which_alternative); "
+;; Do not expect to understand this the first time through.
+[(set_attr "type" "cbranch,multi,multi")
+ (set (attr "length")
+ (if_then_else (eq_attr "alternative" "0")
+;; Loop counter in register case
+;; Short branch has length of 4
+;; Long branch has length of 8, 20, 24 or 28
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28))
+
+;; Loop counter in FP reg case.
+;; Extra goo to deal with additional reload insns.
+ (if_then_else (eq_attr "alternative" "1")
+ (if_then_else (lt (match_dup 3) (pc))
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 24))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 24)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 24))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 28)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 44)
+ (not (match_test "flag_pic"))
+ (const_int 40)]
+ (const_int 48))
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 24)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 28)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 44)
+ (not (match_test "flag_pic"))
+ (const_int 40)]
+ (const_int 48)))
+
+;; Loop counter in memory case.
+;; Extra goo to deal with additional reload insns.
+ (if_then_else (lt (match_dup 3) (pc))
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 12)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 16)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 32)
+ (not (match_test "flag_pic"))
+ (const_int 28)]
+ (const_int 36))
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 12)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 16)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 32)
+ (not (match_test "flag_pic"))
+ (const_int 28)]
+ (const_int 36))))))])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (match_operator 2 "movb_comparison_operator"
+ [(match_operand:SI 1 "register_operand" "r,r,r,r") (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (set (match_operand:SI 0 "reg_before_reload_operand" "=!r,!*f,*m,!*q")
+ (match_dup 1))]
+ ""
+"* return pa_output_movb (operands, insn, which_alternative, 0); "
+;; Do not expect to understand this the first time through.
+[(set_attr "type" "cbranch,multi,multi,multi")
+ (set (attr "length")
+ (if_then_else (eq_attr "alternative" "0")
+;; Loop counter in register case
+;; Short branch has length of 4
+;; Long branch has length of 8, 20, 24 or 28
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28))
+
+;; Loop counter in FP reg case.
+;; Extra goo to deal with additional reload insns.
+ (if_then_else (eq_attr "alternative" "1")
+ (if_then_else (lt (match_dup 3) (pc))
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 12)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 16)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 32)
+ (not (match_test "flag_pic"))
+ (const_int 28)]
+ (const_int 36))
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 12)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 16)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 32)
+ (not (match_test "flag_pic"))
+ (const_int 28)]
+ (const_int 36)))
+
+;; Loop counter in memory or sar case.
+;; Extra goo to deal with additional reload insns.
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 8)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 12)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 28)
+ (not (match_test "flag_pic"))
+ (const_int 24)]
+ (const_int 32)))))])
+
+;; Handle negated branch.
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (match_operator 2 "movb_comparison_operator"
+ [(match_operand:SI 1 "register_operand" "r,r,r,r") (const_int 0)])
+ (pc)
+ (label_ref (match_operand 3 "" ""))))
+ (set (match_operand:SI 0 "reg_before_reload_operand" "=!r,!*f,*m,!*q")
+ (match_dup 1))]
+ ""
+"* return pa_output_movb (operands, insn, which_alternative, 1); "
+;; Do not expect to understand this the first time through.
+[(set_attr "type" "cbranch,multi,multi,multi")
+ (set (attr "length")
+ (if_then_else (eq_attr "alternative" "0")
+;; Loop counter in register case
+;; Short branch has length of 4
+;; Long branch has length of 8
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28))
+
+;; Loop counter in FP reg case.
+;; Extra goo to deal with additional reload insns.
+ (if_then_else (eq_attr "alternative" "1")
+ (if_then_else (lt (match_dup 3) (pc))
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 12)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 12))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 16)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 32)
+ (not (match_test "flag_pic"))
+ (const_int 28)]
+ (const_int 36))
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 12)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 16)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 32)
+ (not (match_test "flag_pic"))
+ (const_int 28)]
+ (const_int 36)))
+
+;; Loop counter in memory or SAR case.
+;; Extra goo to deal with additional reload insns.
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 8)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 12)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 28)
+ (not (match_test "flag_pic"))
+ (const_int 24)]
+ (const_int 32)))))])
+
+(define_insn ""
+ [(set (pc) (label_ref (match_operand 3 "" "" )))
+ (set (match_operand:SI 0 "ireg_operand" "=r")
+ (plus:SI (match_operand:SI 1 "ireg_operand" "r")
+ (match_operand:SI 2 "ireg_or_int5_operand" "rL")))]
+ "(reload_completed && operands[0] == operands[1]) || operands[0] == operands[2]"
+ "*
+{
+ return pa_output_parallel_addb (operands, insn);
+}"
+[(set_attr "type" "parallel_branch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc) (label_ref (match_operand 2 "" "" )))
+ (set (match_operand:SF 0 "ireg_operand" "=r")
+ (match_operand:SF 1 "ireg_or_int5_operand" "rL"))]
+ "reload_completed"
+ "*
+{
+ return pa_output_parallel_movb (operands, insn);
+}"
+[(set_attr "type" "parallel_branch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc) (label_ref (match_operand 2 "" "" )))
+ (set (match_operand:SI 0 "ireg_operand" "=r")
+ (match_operand:SI 1 "ireg_or_int5_operand" "rL"))]
+ "reload_completed"
+ "*
+{
+ return pa_output_parallel_movb (operands, insn);
+}"
+[(set_attr "type" "parallel_branch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc) (label_ref (match_operand 2 "" "" )))
+ (set (match_operand:HI 0 "ireg_operand" "=r")
+ (match_operand:HI 1 "ireg_or_int5_operand" "rL"))]
+ "reload_completed"
+ "*
+{
+ return pa_output_parallel_movb (operands, insn);
+}"
+[(set_attr "type" "parallel_branch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (pc) (label_ref (match_operand 2 "" "" )))
+ (set (match_operand:QI 0 "ireg_operand" "=r")
+ (match_operand:QI 1 "ireg_or_int5_operand" "rL"))]
+ "reload_completed"
+ "*
+{
+ return pa_output_parallel_movb (operands, insn);
+}"
+[(set_attr "type" "parallel_branch")
+ (set (attr "length")
+ (cond [(lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_12BIT_OFFSET))
+ (const_int 4)
+ (lt (abs (minus (match_dup 2) (plus (pc) (const_int 8))))
+ (const_int MAX_17BIT_OFFSET))
+ (const_int 8)
+ (match_test "TARGET_PORTABLE_RUNTIME")
+ (const_int 24)
+ (not (match_test "flag_pic"))
+ (const_int 20)]
+ (const_int 28)))])
+
+(define_insn ""
+ [(set (match_operand 0 "register_operand" "=f")
+ (mult (match_operand 1 "register_operand" "f")
+ (match_operand 2 "register_operand" "f")))
+ (set (match_operand 3 "register_operand" "+f")
+ (plus (match_operand 4 "register_operand" "f")
+ (match_operand 5 "register_operand" "f")))]
+ "TARGET_PA_11 && ! TARGET_SOFT_FLOAT
+ && reload_completed && pa_fmpyaddoperands (operands)"
+ "*
+{
+ if (GET_MODE (operands[0]) == DFmode)
+ {
+ if (rtx_equal_p (operands[3], operands[5]))
+ return \"fmpyadd,dbl %1,%2,%0,%4,%3\";
+ else
+ return \"fmpyadd,dbl %1,%2,%0,%5,%3\";
+ }
+ else
+ {
+ if (rtx_equal_p (operands[3], operands[5]))
+ return \"fmpyadd,sgl %1,%2,%0,%4,%3\";
+ else
+ return \"fmpyadd,sgl %1,%2,%0,%5,%3\";
+ }
+}"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand 3 "register_operand" "+f")
+ (plus (match_operand 4 "register_operand" "f")
+ (match_operand 5 "register_operand" "f")))
+ (set (match_operand 0 "register_operand" "=f")
+ (mult (match_operand 1 "register_operand" "f")
+ (match_operand 2 "register_operand" "f")))]
+ "TARGET_PA_11 && ! TARGET_SOFT_FLOAT
+ && reload_completed && pa_fmpyaddoperands (operands)"
+ "*
+{
+ if (GET_MODE (operands[0]) == DFmode)
+ {
+ if (rtx_equal_p (operands[3], operands[5]))
+ return \"fmpyadd,dbl %1,%2,%0,%4,%3\";
+ else
+ return \"fmpyadd,dbl %1,%2,%0,%5,%3\";
+ }
+ else
+ {
+ if (rtx_equal_p (operands[3], operands[5]))
+ return \"fmpyadd,sgl %1,%2,%0,%4,%3\";
+ else
+ return \"fmpyadd,sgl %1,%2,%0,%5,%3\";
+ }
+}"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand 0 "register_operand" "=f")
+ (mult (match_operand 1 "register_operand" "f")
+ (match_operand 2 "register_operand" "f")))
+ (set (match_operand 3 "register_operand" "+f")
+ (minus (match_operand 4 "register_operand" "f")
+ (match_operand 5 "register_operand" "f")))]
+ "TARGET_PA_11 && ! TARGET_SOFT_FLOAT
+ && reload_completed && pa_fmpysuboperands (operands)"
+ "*
+{
+ if (GET_MODE (operands[0]) == DFmode)
+ return \"fmpysub,dbl %1,%2,%0,%5,%3\";
+ else
+ return \"fmpysub,sgl %1,%2,%0,%5,%3\";
+}"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+(define_insn ""
+ [(set (match_operand 3 "register_operand" "+f")
+ (minus (match_operand 4 "register_operand" "f")
+ (match_operand 5 "register_operand" "f")))
+ (set (match_operand 0 "register_operand" "=f")
+ (mult (match_operand 1 "register_operand" "f")
+ (match_operand 2 "register_operand" "f")))]
+ "TARGET_PA_11 && ! TARGET_SOFT_FLOAT
+ && reload_completed && pa_fmpysuboperands (operands)"
+ "*
+{
+ if (GET_MODE (operands[0]) == DFmode)
+ return \"fmpysub,dbl %1,%2,%0,%5,%3\";
+ else
+ return \"fmpysub,sgl %1,%2,%0,%5,%3\";
+}"
+ [(set_attr "type" "fpalu")
+ (set_attr "length" "4")])
+
+;; The following two patterns are used by the trampoline code for nested
+;; functions. They flush the I and D cache lines from the start address
+;; (operand0) to the end address (operand1). No lines are flushed if the
+;; end address is less than the start address (unsigned).
+;;
+;; Because the range of memory flushed is variable and the size of a MEM
+;; can only be a CONST_INT, the patterns specify that they perform an
+;; unspecified volatile operation on all memory.
+;;
+;; The address range for an icache flush must lie within a single
+;; space on targets with non-equivalent space registers.
+;;
+;; Operand 0 contains the start address.
+;; Operand 1 contains the end address.
+;; Operand 2 contains the line length to use.
+(define_insn "dcacheflush<P:mode>"
+ [(const_int 1)
+ (unspec_volatile [(mem:BLK (scratch))] UNSPECV_DCACHE)
+ (use (match_operand 0 "pmode_register_operand" "r"))
+ (use (match_operand 1 "pmode_register_operand" "r"))
+ (use (match_operand 2 "pmode_register_operand" "r"))
+ (clobber (match_scratch:P 3 "=&0"))]
+ ""
+ "cmpb,<dwc><<=,n %3,%1,.\;fdc,m %2(%3)\;sync"
+ [(set_attr "type" "multi")
+ (set_attr "length" "12")])
+
+(define_insn "icacheflush<P:mode>"
+ [(const_int 2)
+ (unspec_volatile [(mem:BLK (scratch))] UNSPECV_ICACHE)
+ (use (match_operand 0 "pmode_register_operand" "r"))
+ (use (match_operand 1 "pmode_register_operand" "r"))
+ (use (match_operand 2 "pmode_register_operand" "r"))
+ (clobber (match_operand 3 "pmode_register_operand" "=&r"))
+ (clobber (match_operand 4 "pmode_register_operand" "=&r"))
+ (clobber (match_scratch:P 5 "=&0"))]
+ ""
+ "mfsp %%sr0,%4\;ldsid (%5),%3\;mtsp %3,%%sr0\;cmpb,<dwc><<=,n %5,%1,.\;fic,m %2(%%sr0,%5)\;sync\;mtsp %4,%%sr0\;nop\;nop\;nop\;nop\;nop\;nop"
+ [(set_attr "type" "multi")
+ (set_attr "length" "52")])
+
+;; An out-of-line prologue.
+(define_insn "outline_prologue_call"
+ [(unspec_volatile [(const_int 0)] UNSPECV_OPC)
+ (clobber (reg:SI 31))
+ (clobber (reg:SI 22))
+ (clobber (reg:SI 21))
+ (clobber (reg:SI 20))
+ (clobber (reg:SI 19))
+ (clobber (reg:SI 1))]
+ ""
+ "*
+{
+
+ /* We need two different versions depending on whether or not we
+ need a frame pointer. Also note that we return to the instruction
+ immediately after the branch rather than two instructions after the
+ break as normally is the case. */
+ if (frame_pointer_needed)
+ {
+ /* Must import the magic millicode routine(s). */
+ output_asm_insn (\".IMPORT __outline_prologue_fp,MILLICODE\", NULL);
+
+ if (TARGET_PORTABLE_RUNTIME)
+ {
+ output_asm_insn (\"ldil L'__outline_prologue_fp,%%r31\", NULL);
+ output_asm_insn (\"ble,n R'__outline_prologue_fp(%%sr0,%%r31)\",
+ NULL);
+ }
+ else
+ output_asm_insn (\"{bl|b,l},n __outline_prologue_fp,%%r31\", NULL);
+ }
+ else
+ {
+ /* Must import the magic millicode routine(s). */
+ output_asm_insn (\".IMPORT __outline_prologue,MILLICODE\", NULL);
+
+ if (TARGET_PORTABLE_RUNTIME)
+ {
+ output_asm_insn (\"ldil L'__outline_prologue,%%r31\", NULL);
+ output_asm_insn (\"ble,n R'__outline_prologue(%%sr0,%%r31)\", NULL);
+ }
+ else
+ output_asm_insn (\"{bl|b,l},n __outline_prologue,%%r31\", NULL);
+ }
+ return \"\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+;; An out-of-line epilogue.
+(define_insn "outline_epilogue_call"
+ [(unspec_volatile [(const_int 1)] UNSPECV_OEC)
+ (use (reg:SI 29))
+ (use (reg:SI 28))
+ (clobber (reg:SI 31))
+ (clobber (reg:SI 22))
+ (clobber (reg:SI 21))
+ (clobber (reg:SI 20))
+ (clobber (reg:SI 19))
+ (clobber (reg:SI 2))
+ (clobber (reg:SI 1))]
+ ""
+ "*
+{
+
+ /* We need two different versions depending on whether or not we
+ need a frame pointer. Also note that we return to the instruction
+ immediately after the branch rather than two instructions after the
+ break as normally is the case. */
+ if (frame_pointer_needed)
+ {
+ /* Must import the magic millicode routine. */
+ output_asm_insn (\".IMPORT __outline_epilogue_fp,MILLICODE\", NULL);
+
+ /* The out-of-line prologue will make sure we return to the right
+ instruction. */
+ if (TARGET_PORTABLE_RUNTIME)
+ {
+ output_asm_insn (\"ldil L'__outline_epilogue_fp,%%r31\", NULL);
+ output_asm_insn (\"ble,n R'__outline_epilogue_fp(%%sr0,%%r31)\",
+ NULL);
+ }
+ else
+ output_asm_insn (\"{bl|b,l},n __outline_epilogue_fp,%%r31\", NULL);
+ }
+ else
+ {
+ /* Must import the magic millicode routine. */
+ output_asm_insn (\".IMPORT __outline_epilogue,MILLICODE\", NULL);
+
+ /* The out-of-line prologue will make sure we return to the right
+ instruction. */
+ if (TARGET_PORTABLE_RUNTIME)
+ {
+ output_asm_insn (\"ldil L'__outline_epilogue,%%r31\", NULL);
+ output_asm_insn (\"ble,n R'__outline_epilogue(%%sr0,%%r31)\", NULL);
+ }
+ else
+ output_asm_insn (\"{bl|b,l},n __outline_epilogue,%%r31\", NULL);
+ }
+ return \"\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+;; Given a function pointer, canonicalize it so it can be
+;; reliably compared to another function pointer. */
+(define_expand "canonicalize_funcptr_for_compare"
+ [(set (reg:SI 26) (match_operand:SI 1 "register_operand" ""))
+ (parallel [(set (reg:SI 29) (unspec:SI [(reg:SI 26)] UNSPEC_CFFC))
+ (clobber (match_dup 2))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 22))
+ (clobber (reg:SI 31))])
+ (set (match_operand:SI 0 "register_operand" "")
+ (reg:SI 29))]
+ "!TARGET_PORTABLE_RUNTIME && !TARGET_64BIT"
+ "
+{
+ if (TARGET_ELF32)
+ {
+ rtx canonicalize_funcptr_for_compare_libfunc
+ = init_one_libfunc (CANONICALIZE_FUNCPTR_FOR_COMPARE_LIBCALL);
+
+ emit_library_call_value (canonicalize_funcptr_for_compare_libfunc,
+ operands[0], LCT_NORMAL, Pmode,
+ 1, operands[1], Pmode);
+ DONE;
+ }
+
+ operands[2] = gen_reg_rtx (SImode);
+ if (GET_CODE (operands[1]) != REG)
+ {
+ rtx tmp = gen_reg_rtx (Pmode);
+ emit_move_insn (tmp, operands[1]);
+ operands[1] = tmp;
+ }
+}")
+
+(define_insn "*$$sh_func_adrs"
+ [(set (reg:SI 29) (unspec:SI [(reg:SI 26)] UNSPEC_CFFC))
+ (clobber (match_operand:SI 0 "register_operand" "=a"))
+ (clobber (reg:SI 26))
+ (clobber (reg:SI 22))
+ (clobber (reg:SI 31))]
+ "!TARGET_64BIT"
+ "*
+{
+ int length = get_attr_length (insn);
+ rtx xoperands[2];
+
+ xoperands[0] = GEN_INT (length - 8);
+ xoperands[1] = GEN_INT (length - 16);
+
+ /* Must import the magic millicode routine. */
+ output_asm_insn (\".IMPORT $$sh_func_adrs,MILLICODE\", NULL);
+
+ /* This is absolutely amazing.
+
+ First, copy our input parameter into %r29 just in case we don't
+ need to call $$sh_func_adrs. */
+ output_asm_insn (\"copy %%r26,%%r29\", NULL);
+ output_asm_insn (\"{extru|extrw,u} %%r26,31,2,%%r31\", NULL);
+
+ /* Next, examine the low two bits in %r26, if they aren't 0x2, then
+ we use %r26 unchanged. */
+ output_asm_insn (\"{comib|cmpib},<>,n 2,%%r31,.+%0\", xoperands);
+ output_asm_insn (\"ldi 4096,%%r31\", NULL);
+
+ /* Next, compare %r26 with 4096, if %r26 is less than or equal to
+ 4096, then again we use %r26 unchanged. */
+ output_asm_insn (\"{comb|cmpb},<<,n %%r26,%%r31,.+%1\", xoperands);
+
+ /* Finally, call $$sh_func_adrs to extract the function's real add24. */
+ return pa_output_millicode_call (insn,
+ gen_rtx_SYMBOL_REF (SImode,
+ \"$$sh_func_adrs\"));
+}"
+ [(set_attr "type" "sh_func_adrs")
+ (set (attr "length")
+ (cond [(and (const_int 0) (eq (const_int 0) (pc))) (const_int 28)]
+ (plus (symbol_ref "pa_attr_length_millicode_call (insn)")
+ (const_int 20))))])
+
+;; On the PA, the PIC register is call clobbered, so it must
+;; be saved & restored around calls by the caller. If the call
+;; doesn't return normally (nonlocal goto, or an exception is
+;; thrown), then the code at the exception handler label must
+;; restore the PIC register.
+(define_expand "exception_receiver"
+ [(const_int 4)]
+ "flag_pic"
+ "
+{
+ /* On the 64-bit port, we need a blockage because there is
+ confusion regarding the dependence of the restore on the
+ frame pointer. As a result, the frame pointer and pic
+ register restores sometimes are interchanged erroneously. */
+ if (TARGET_64BIT)
+ emit_insn (gen_blockage ());
+ /* Restore the PIC register using hppa_pic_save_rtx (). The
+ PIC register is not saved in the frame in 64-bit ABI. */
+ emit_move_insn (pic_offset_table_rtx, hppa_pic_save_rtx ());
+ emit_insn (gen_blockage ());
+ DONE;
+}")
+
+(define_expand "builtin_setjmp_receiver"
+ [(label_ref (match_operand 0 "" ""))]
+ "flag_pic"
+ "
+{
+ if (TARGET_64BIT)
+ emit_insn (gen_blockage ());
+ /* Restore the PIC register. Hopefully, this will always be from
+ a stack slot. The only registers that are valid after a
+ builtin_longjmp are the stack and frame pointers. */
+ emit_move_insn (pic_offset_table_rtx, hppa_pic_save_rtx ());
+ emit_insn (gen_blockage ());
+ DONE;
+}")
+
+;; Allocate new stack space and update the saved stack pointer in the
+;; frame marker. The HP C compilers also copy additional words in the
+;; frame marker. The 64-bit compiler copies words at -48, -32 and -24.
+;; The 32-bit compiler copies the word at -16 (Static Link). We
+;; currently don't copy these values.
+;;
+;; Since the copy of the frame marker can't be done atomically, I
+;; suspect that using it for unwind purposes may be somewhat unreliable.
+;; The HP compilers appear to raise the stack and copy the frame
+;; marker in a strict instruction sequence. This suggests that the
+;; unwind library may check for an alloca sequence when ALLOCA_FRAME
+;; is set in the callinfo data. We currently don't set ALLOCA_FRAME
+;; as GAS doesn't support it, or try to keep the instructions emitted
+;; here in strict sequence.
+(define_expand "allocate_stack"
+ [(match_operand 0 "" "")
+ (match_operand 1 "" "")]
+ ""
+ "
+{
+ rtx addr;
+
+ /* Since the stack grows upward, we need to store virtual_stack_dynamic_rtx
+ in operand 0 before adjusting the stack. */
+ emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
+ anti_adjust_stack (operands[1]);
+ if (TARGET_HPUX_UNWIND_LIBRARY)
+ {
+ addr = gen_rtx_PLUS (word_mode, stack_pointer_rtx,
+ GEN_INT (TARGET_64BIT ? -8 : -4));
+ emit_move_insn (gen_rtx_MEM (word_mode, addr), hard_frame_pointer_rtx);
+ }
+ if (!TARGET_64BIT && flag_pic)
+ {
+ rtx addr = gen_rtx_PLUS (word_mode, stack_pointer_rtx, GEN_INT (-32));
+ emit_move_insn (gen_rtx_MEM (word_mode, addr), pic_offset_table_rtx);
+ }
+ DONE;
+}")
+
+(define_expand "prefetch"
+ [(match_operand 0 "address_operand" "")
+ (match_operand 1 "const_int_operand" "")
+ (match_operand 2 "const_int_operand" "")]
+ "TARGET_PA_20"
+{
+ operands[0] = copy_addr_to_reg (operands[0]);
+ emit_insn (gen_prefetch_20 (operands[0], operands[1], operands[2]));
+ DONE;
+})
+
+(define_insn "prefetch_20"
+ [(prefetch (match_operand 0 "pmode_register_operand" "r")
+ (match_operand:SI 1 "const_int_operand" "n")
+ (match_operand:SI 2 "const_int_operand" "n"))]
+ "TARGET_PA_20"
+{
+ /* The SL cache-control completer indicates good spatial locality but
+ poor temporal locality. The ldw instruction with a target of general
+ register 0 prefetches a cache line for a read. The ldd instruction
+ prefetches a cache line for a write. */
+ static const char * const instr[2][2] = {
+ {
+ "ldw,sl 0(%0),%%r0",
+ "ldd,sl 0(%0),%%r0"
+ },
+ {
+ "ldw 0(%0),%%r0",
+ "ldd 0(%0),%%r0"
+ }
+ };
+ int read_or_write = INTVAL (operands[1]) == 0 ? 0 : 1;
+ int locality = INTVAL (operands[2]) == 0 ? 0 : 1;
+
+ return instr [locality][read_or_write];
+}
+ [(set_attr "type" "load")
+ (set_attr "length" "4")])
+
+;; TLS Support
+(define_insn "tgd_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand 1 "tgd_symbolic_operand" "")] UNSPEC_TLSGD))
+ (clobber (reg:SI 1))
+ (use (reg:SI 27))]
+ ""
+ "*
+{
+ return \"addil LR'%1-$tls_gdidx$,%%r27\;ldo RR'%1-$tls_gdidx$(%%r1),%0\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+(define_insn "tgd_load_pic"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand 1 "tgd_symbolic_operand" "")] UNSPEC_TLSGD_PIC))
+ (clobber (reg:SI 1))
+ (use (reg:SI 19))]
+ ""
+ "*
+{
+ return \"addil LT'%1-$tls_gdidx$,%%r19\;ldo RT'%1-$tls_gdidx$(%%r1),%0\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+(define_insn "tld_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand 1 "tld_symbolic_operand" "")] UNSPEC_TLSLDM))
+ (clobber (reg:SI 1))
+ (use (reg:SI 27))]
+ ""
+ "*
+{
+ return \"addil LR'%1-$tls_ldidx$,%%r27\;ldo RR'%1-$tls_ldidx$(%%r1),%0\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+(define_insn "tld_load_pic"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand 1 "tld_symbolic_operand" "")] UNSPEC_TLSLDM_PIC))
+ (clobber (reg:SI 1))
+ (use (reg:SI 19))]
+ ""
+ "*
+{
+ return \"addil LT'%1-$tls_ldidx$,%%r19\;ldo RT'%1-$tls_ldidx$(%%r1),%0\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+(define_insn "tld_offset_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (unspec:SI [(match_operand 1 "tld_symbolic_operand" "")]
+ UNSPEC_TLSLDO)
+ (match_operand:SI 2 "register_operand" "r")))
+ (clobber (reg:SI 1))]
+ ""
+ "*
+{
+ return \"addil LR'%1-$tls_dtpoff$,%2\;ldo RR'%1-$tls_dtpoff$(%%r1),%0\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+(define_insn "tp_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(const_int 0)] UNSPEC_TP))]
+ ""
+ "mfctl %%cr27,%0"
+ [(set_attr "type" "multi")
+ (set_attr "length" "4")])
+
+(define_insn "tie_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand 1 "tie_symbolic_operand" "")] UNSPEC_TLSIE))
+ (clobber (reg:SI 1))
+ (use (reg:SI 27))]
+ ""
+ "*
+{
+ return \"addil LR'%1-$tls_ieoff$,%%r27\;ldw RR'%1-$tls_ieoff$(%%r1),%0\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+(define_insn "tie_load_pic"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand 1 "tie_symbolic_operand" "")] UNSPEC_TLSIE_PIC))
+ (clobber (reg:SI 1))
+ (use (reg:SI 19))]
+ ""
+ "*
+{
+ return \"addil LT'%1-$tls_ieoff$,%%r19\;ldw RT'%1-$tls_ieoff$(%%r1),%0\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+(define_insn "tle_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (unspec:SI [(match_operand 1 "tle_symbolic_operand" "")]
+ UNSPEC_TLSLE)
+ (match_operand:SI 2 "register_operand" "r")))
+ (clobber (reg:SI 1))]
+ ""
+ "addil LR'%1-$tls_leoff$,%2\;ldo RR'%1-$tls_leoff$(%%r1),%0"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])