diff options
Diffstat (limited to 'contrib/gcc/config/alpha/alpha.md')
-rw-r--r-- | contrib/gcc/config/alpha/alpha.md | 3300 |
1 files changed, 2377 insertions, 923 deletions
diff --git a/contrib/gcc/config/alpha/alpha.md b/contrib/gcc/config/alpha/alpha.md index 72c54eee371b..87ebf95e168f 100644 --- a/contrib/gcc/config/alpha/alpha.md +++ b/contrib/gcc/config/alpha/alpha.md @@ -1,5 +1,5 @@ ;; Machine description for DEC Alpha for GNU C compiler -;; Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +;; Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. ;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) ;; This file is part of GNU CC. @@ -20,71 +20,396 @@ ;; Boston, MA 02111-1307, USA. ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;; Uses of UNSPEC in this file: +;; +;; 0 arg_home +;; 1 cttz +;; 2 insxh +;; 3 mskxh +;; 4 cvtlq +;; 5 cvtql +;; +;; UNSPEC_VOLATILE: +;; +;; 0 imb +;; 1 blockage +;; 2 builtin_setjmp_receiver +;; 3 builtin_longjmp +;; 4 trapb +;; 5 prologue_stack_probe_loop +;; Processor type -- this attribute must exactly match the processor_type +;; enumeration in alpha.h. + +(define_attr "cpu" "ev4,ev5,ev6" + (const (symbol_ref "alpha_cpu"))) + ;; Define an insn type attribute. This is used in function unit delay ;; computations, among other purposes. For the most part, we use the names ;; defined in the EV4 documentation, but add a few that we have to know about ;; separately. (define_attr "type" - "ld,st,ibr,fbr,jsr,iaddlog,shiftcm,icmp,imull,imulq,fpop,fdivs,fdivt,ldsym,isubr" - (const_string "shiftcm")) - -;; We include four function units: ABOX, which computes the address, -;; BBOX, used for branches, EBOX, used for integer operations, and FBOX, -;; used for FP operations. -;; -;; We assume that we have been successful in getting double issues and -;; hence multiply all costs by two insns per cycle. The minimum time in -;; a function unit is 2 cycle, which will tend to produce the double -;; issues. + "ild,fld,ldsym,ist,fst,ibr,fbr,jsr,iadd,ilog,shift,icmov,fcmov,icmp,imul,fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof" + (const_string "iadd")) -;; Memory delivers its result in three cycles. -(define_function_unit "abox" 1 0 (eq_attr "type" "ld,ldsym,st") 6 2) +;; Define the operand size an insn operates on. Used primarily by mul +;; and div operations that have size dependant timings. -;; Branches have no delay cost, but do tie up the unit for two cycles. -(define_function_unit "bbox" 1 1 (eq_attr "type" "ibr,fbr,jsr") 4 4) +(define_attr "opsize" "si,di,udi" (const_string "di")) -;; Arithmetic insns are normally have their results available after two -;; cycles. There are a number of exceptions. They are encoded in -;; ADJUST_COST. Some of the other insns have similar exceptions. +;; The TRAP_TYPE attribute marks instructions that may generate traps +;; (which are imprecise and may need a trapb if software completion +;; is desired). -(define_function_unit "ebox" 1 0 (eq_attr "type" "iaddlog,shiftcm,icmp") 4 2) +(define_attr "trap" "no,yes" (const_string "no")) -;; These really don't take up the integer pipeline, but they do occupy -;; IBOX1; we approximate here. +;; The length of an instruction sequence in bytes. -(define_function_unit "ebox" 1 0 (eq_attr "type" "imull") 42 2) -(define_function_unit "ebox" 1 0 (eq_attr "type" "imulq") 46 2) - -(define_function_unit "imult" 1 0 (eq_attr "type" "imull") 42 38) -(define_function_unit "imult" 1 0 (eq_attr "type" "imulq") 46 42) - -(define_function_unit "fbox" 1 0 (eq_attr "type" "fpop") 12 2) - -(define_function_unit "fbox" 1 0 (eq_attr "type" "fdivs") 68 0) -(define_function_unit "fbox" 1 0 (eq_attr "type" "fdivt") 126 0) +(define_attr "length" "" (const_int 4)) + +;; On EV4 there are two classes of resources to consider: resources needed +;; to issue, and resources needed to execute. IBUS[01] are in the first +;; category. ABOX, BBOX, EBOX, FBOX, IMUL & FDIV make up the second. +;; (There are a few other register-like resources, but ...) + +; First, describe all of the issue constraints with single cycle delays. +; All insns need a bus, but all except loads require one or the other. +(define_function_unit "ev4_ibus0" 1 0 + (and (eq_attr "cpu" "ev4") + (eq_attr "type" "fst,fbr,iadd,imul,ilog,shift,icmov,icmp")) + 1 1) + +(define_function_unit "ev4_ibus1" 1 0 + (and (eq_attr "cpu" "ev4") + (eq_attr "type" "ist,ibr,jsr,fadd,fcmov,fcpys,fmul,fdiv,misc")) + 1 1) + +; Memory delivers its result in three cycles. Actually return one and +; take care of this in adjust_cost, since we want to handle user-defined +; memory latencies. +(define_function_unit "ev4_abox" 1 0 + (and (eq_attr "cpu" "ev4") + (eq_attr "type" "ild,fld,ldsym,ist,fst")) + 1 1) + +; Branches have no delay cost, but do tie up the unit for two cycles. +(define_function_unit "ev4_bbox" 1 1 + (and (eq_attr "cpu" "ev4") + (eq_attr "type" "ibr,fbr,jsr")) + 2 2) + +; Arithmetic insns are normally have their results available after +; two cycles. There are a number of exceptions. They are encoded in +; ADJUST_COST. Some of the other insns have similar exceptions. +(define_function_unit "ev4_ebox" 1 0 + (and (eq_attr "cpu" "ev4") + (eq_attr "type" "iadd,ilog,shift,icmov,icmp,misc")) + 2 1) + +(define_function_unit "imul" 1 0 + (and (eq_attr "cpu" "ev4") + (and (eq_attr "type" "imul") + (eq_attr "opsize" "si"))) + 21 19) + +(define_function_unit "imul" 1 0 + (and (eq_attr "cpu" "ev4") + (and (eq_attr "type" "imul") + (eq_attr "opsize" "!si"))) + 23 21) + +(define_function_unit "ev4_fbox" 1 0 + (and (eq_attr "cpu" "ev4") + (eq_attr "type" "fadd,fmul,fcpys,fcmov")) + 6 1) + +(define_function_unit "fdiv" 1 0 + (and (eq_attr "cpu" "ev4") + (and (eq_attr "type" "fdiv") + (eq_attr "opsize" "si"))) + 34 30) + +(define_function_unit "fdiv" 1 0 + (and (eq_attr "cpu" "ev4") + (and (eq_attr "type" "fdiv") + (eq_attr "opsize" "di"))) + 63 59) + +;; EV5 scheduling. EV5 can issue 4 insns per clock. +;; +;; EV5 has two asymetric integer units. Model this with E0 & E1 along +;; with the combined resource EBOX. + +(define_function_unit "ev5_ebox" 2 0 + (and (eq_attr "cpu" "ev5") + (eq_attr "type" "!fbr,fcmov,fadd,fmul,fcpys,fdiv")) + 1 1) + +; Memory takes at least 2 clocks. Return one from here and fix up with +; user-defined latencies in adjust_cost. +; ??? How to: "An instruction of class LD cannot be issued in the _second_ +; cycle after an instruction of class ST is issued." +(define_function_unit "ev5_ebox" 2 0 + (and (eq_attr "cpu" "ev5") + (eq_attr "type" "ild,fld,ldsym")) + 1 1) + +; Stores, shifts, multiplies can only issue to E0 +(define_function_unit "ev5_e0" 1 0 + (and (eq_attr "cpu" "ev5") + (eq_attr "type" "ist,fst,shift,imul")) + 1 1) + +; Motion video insns also issue only to E0, and take two ticks. +(define_function_unit "ev5_e0" 1 0 + (and (eq_attr "cpu" "ev5") + (eq_attr "type" "mvi")) + 2 1) + +; Conditional moves always take 2 ticks. +(define_function_unit "ev5_ebox" 2 0 + (and (eq_attr "cpu" "ev5") + (eq_attr "type" "icmov")) + 2 1) + +; Branches can only issue to E1 +(define_function_unit "ev5_e1" 1 0 + (and (eq_attr "cpu" "ev5") + (eq_attr "type" "ibr,jsr")) + 1 1) + +; Multiplies also use the integer multiplier. +; ??? How to: "No instruction can be issued to pipe E0 exactly two +; cycles before an integer multiplication completes." +(define_function_unit "imul" 1 0 + (and (eq_attr "cpu" "ev5") + (and (eq_attr "type" "imul") + (eq_attr "opsize" "si"))) + 8 4) + +(define_function_unit "imul" 1 0 + (and (eq_attr "cpu" "ev5") + (and (eq_attr "type" "imul") + (eq_attr "opsize" "di"))) + 12 8) + +(define_function_unit "imul" 1 0 + (and (eq_attr "cpu" "ev5") + (and (eq_attr "type" "imul") + (eq_attr "opsize" "udi"))) + 14 8) + +;; Similarly for the FPU we have two asymetric units. But fcpys can issue +;; on either so we have to play the game again. + +(define_function_unit "ev5_fbox" 2 0 + (and (eq_attr "cpu" "ev5") + (eq_attr "type" "fadd,fcmov,fmul,fcpys,fbr,fdiv")) + 4 1) + +(define_function_unit "ev5_fm" 1 0 + (and (eq_attr "cpu" "ev5") + (eq_attr "type" "fmul")) + 4 1) + +; Add and cmov as you would expect; fbr never produces a result; +; fdiv issues through fa to the divider, +(define_function_unit "ev5_fa" 1 0 + (and (eq_attr "cpu" "ev5") + (eq_attr "type" "fadd,fcmov,fbr,fdiv")) + 4 1) + +; ??? How to: "No instruction can be issued to pipe FA exactly five +; cycles before a floating point divide completes." +(define_function_unit "fdiv" 1 0 + (and (eq_attr "cpu" "ev5") + (and (eq_attr "type" "fdiv") + (eq_attr "opsize" "si"))) + 15 15) ; 15 to 31 data dependant + +(define_function_unit "fdiv" 1 0 + (and (eq_attr "cpu" "ev5") + (and (eq_attr "type" "fdiv") + (eq_attr "opsize" "di"))) + 22 22) ; 22 to 60 data dependant + +;; EV6 scheduling. EV6 can issue 4 insns per clock. +;; +;; EV6 has two symmetric pairs ("clusters") of two asymetric integer units +;; ("upper" and "lower"), yielding pipe names U0, U1, L0, L1. + +;; Conditional moves decompose into two independant primitives, each +;; taking one cycle. Since ev6 is out-of-order, we can't see anything +;; but two cycles. +(define_function_unit "ev6_ebox" 4 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "icmov")) + 2 1) + +(define_function_unit "ev6_ebox" 4 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "!fbr,fcmov,fadd,fmul,fcpys,fdiv,fsqrt")) + 1 1) + +;; Integer loads take at least 3 clocks, and only issue to lower units. +;; Return one from here and fix up with user-defined latencies in adjust_cost. +(define_function_unit "ev6_l" 2 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "ild,ldsym,ist,fst")) + 1 1) + +;; FP loads take at least 4 clocks. Return two from here... +(define_function_unit "ev6_l" 2 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "fld")) + 2 1) + +;; Motion video insns also issue only to U0, and take three ticks. +(define_function_unit "ev6_u0" 1 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "mvi")) + 3 1) + +(define_function_unit "ev6_u" 2 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "mvi")) + 3 1) + +;; Shifts issue to either upper pipe. +(define_function_unit "ev6_u" 2 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "shift")) + 1 1) + +;; Multiplies issue only to U1, and all take 7 ticks. +;; Rather than create a new function unit just for U1, reuse IMUL +(define_function_unit "imul" 1 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "imul")) + 7 1) + +(define_function_unit "ev6_u" 2 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "imul")) + 7 1) + +;; Branches issue to either upper pipe +(define_function_unit "ev6_u" 2 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "ibr")) + 3 1) + +;; Calls only issue to L0. +(define_function_unit "ev6_l0" 1 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "jsr")) + 1 1) + +(define_function_unit "ev6_l" 2 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "jsr")) + 1 1) + +;; Ftoi/itof only issue to lower pipes +(define_function_unit "ev6_l" 2 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "ftoi")) + 3 1) + +(define_function_unit "ev6_l" 2 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "itof")) + 4 1) + +;; For the FPU we are very similar to EV5, except there's no insn that +;; can issue to fm & fa, so we get to leave that out. + +(define_function_unit "ev6_fm" 1 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "fmul")) + 4 1) + +(define_function_unit "ev6_fa" 1 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "fadd,fcpys,fbr,fdiv,fsqrt")) + 4 1) + +(define_function_unit "ev6_fa" 1 0 + (and (eq_attr "cpu" "ev6") + (eq_attr "type" "fcmov")) + 8 1) + +(define_function_unit "fdiv" 1 0 + (and (eq_attr "cpu" "ev6") + (and (eq_attr "type" "fdiv") + (eq_attr "opsize" "si"))) + 12 10) + +(define_function_unit "fdiv" 1 0 + (and (eq_attr "cpu" "ev6") + (and (eq_attr "type" "fdiv") + (eq_attr "opsize" "di"))) + 15 13) + +(define_function_unit "fsqrt" 1 0 + (and (eq_attr "cpu" "ev6") + (and (eq_attr "type" "fsqrt") + (eq_attr "opsize" "si"))) + 16 14) + +(define_function_unit "fsqrt" 1 0 + (and (eq_attr "cpu" "ev6") + (and (eq_attr "type" "fsqrt") + (eq_attr "opsize" "di"))) + 32 30) + +; ??? The FPU communicates with memory and the integer register file +; via two fp store units. We need a slot in the fst immediately, and +; a slot in LOW after the operand data is ready. At which point the +; data may be moved either to the store queue or the integer register +; file and the insn retired. -(define_function_unit "divider" 1 0 (eq_attr "type" "fdivs") 68 60) -(define_function_unit "divider" 1 0 (eq_attr "type" "fdivt") 126 118) ;; First define the arithmetic insns. Note that the 32-bit forms also ;; sign-extend. -;; Note that we can do sign extensions in both FP and integer registers. -;; However, the result must be in the same type of register as the input. -;; The register preferencing code can't handle this case very well, so, for -;; now, don't let the FP case show up here for preferencing. Also, -;; sign-extends in FP registers take two instructions. +;; Handle 32-64 bit extension from memory to a floating point register +;; specially, since this ocurrs frequently in int->double conversions. +;; This is done with a define_split after reload converting the plain +;; sign-extension into a load+unspec, which of course results in lds+cvtlq. +;; +;; Note that while we must retain the =f case in the insn for reload's +;; benefit, it should be eliminated after reload, so we should never emit +;; code for that case. But we don't reject the possibility. + (define_insn "extendsidi2" - [(set (match_operand:DI 0 "register_operand" "=r,r,*f") - (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m,*f")))] + [(set (match_operand:DI 0 "register_operand" "=r,r,?f") + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m,m")))] "" "@ addl %1,$31,%0 ldl %0,%1 - cvtql %1,%0\;cvtlq %0,%0" - [(set_attr "type" "iaddlog,ld,fpop")]) + lds %0,%1\;cvtlq %0,%0" + [(set_attr "type" "iadd,ild,fld") + (set_attr "length" "*,*,8")]) + +;; Due to issues with CLASS_CANNOT_CHANGE_SIZE, we cannot use a subreg here. +(define_split + [(set (match_operand:DI 0 "hard_fp_register_operand" "") + (sign_extend:DI (match_operand:SI 1 "memory_operand" "")))] + "reload_completed" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (unspec:DI [(match_dup 2)] 4))] + "operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]));") + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=f") + (unspec:DI [(match_operand:SI 1 "register_operand" "f")] 4))] + "" + "cvtlq %1,%0" + [(set_attr "type" "fadd")]) ;; Do addsi3 the way expand_binop would do if we didn't have one. This ;; generates better code. We have the anonymous addsi3 pattern below in @@ -95,10 +420,10 @@ (match_operand:SI 2 "add_operand" "")))] "" " -{ emit_insn (gen_rtx (SET, VOIDmode, gen_lowpart (DImode, operands[0]), - gen_rtx (PLUS, DImode, - gen_lowpart (DImode, operands[1]), - gen_lowpart (DImode, operands[2])))); +{ emit_insn (gen_rtx_SET (VOIDmode, gen_lowpart (DImode, operands[0]), + gen_rtx_PLUS (DImode, + gen_lowpart (DImode, operands[1]), + gen_lowpart (DImode, operands[2])))); DONE; } ") @@ -111,8 +436,7 @@ addl %r1,%2,%0 subl %r1,%n2,%0 lda %0,%2(%r1) - ldah %0,%h2(%r1)" - [(set_attr "type" "iaddlog")]) + ldah %0,%h2(%r1)") (define_split [(set (match_operand:SI 0 "register_operand" "") @@ -139,8 +463,7 @@ "" "@ addl %r1,%2,%0 - subl %r1,%n2,%0" - [(set_attr "type" "iaddlog")]) + subl %r1,%n2,%0") (define_split [(set (match_operand:DI 0 "register_operand" "") @@ -179,8 +502,8 @@ (set (match_dup 0) (sign_extend:DI (plus:SI (match_dup 7) (match_dup 4))))] " { - operands[6] = gen_rtx (GET_CODE (operands[1]), DImode, - operands[2], operands[3]); + operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[1]), DImode, + operands[2], operands[3]); operands[7] = gen_lowpart (SImode, operands[5]); }") @@ -193,8 +516,7 @@ addq %r1,%2,%0 subq %r1,%n2,%0 lda %0,%2(%r1) - ldah %0,%h2(%r1)" - [(set_attr "type" "iaddlog")]) + ldah %0,%h2(%r1)") ;; Don't do this if we are adjusting SP since we don't want to do ;; it in two steps. @@ -224,8 +546,7 @@ "" "@ s%2addl %r1,%3,%0 - s%2subl %r1,%n3,%0" - [(set_attr "type" "iaddlog")]) + s%2subl %r1,%n3,%0") (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r,r") @@ -236,8 +557,7 @@ "" "@ s%2addl %r1,%3,%0 - s%2subl %r1,%n3,%0" - [(set_attr "type" "iaddlog")]) + s%2subl %r1,%n3,%0") (define_split [(set (match_operand:DI 0 "register_operand" "") @@ -255,8 +575,8 @@ (match_dup 5))))] " { - operands[7] = gen_rtx (GET_CODE (operands[1]), DImode, - operands[2], operands[3]); + operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[1]), DImode, + operands[2], operands[3]); operands[8] = gen_lowpart (SImode, operands[6]); }") @@ -268,8 +588,7 @@ "" "@ s%2addq %r1,%3,%0 - s%2subq %1,%n3,%0" - [(set_attr "type" "iaddlog")]) + s%2subq %1,%n3,%0") ;; These variants of the above insns can occur if the third operand ;; is the frame pointer. This is a kludge, but there doesn't @@ -281,8 +600,7 @@ (match_operand:DI 2 "some_operand" "r")) (match_operand:DI 3 "some_operand" "rIOKL")))] "reload_in_progress" - "#" - [(set_attr "type" "iaddlog")]) + "#") (define_split [(set (match_operand:DI 0 "register_operand" "") @@ -301,8 +619,7 @@ (match_operand:SI 3 "some_operand" "r")) (match_operand:SI 4 "some_operand" "rIOKL")))] "reload_in_progress" - "#" - [(set_attr "type" "iaddlog")]) + "#") (define_split [(set (match_operand:SI 0 "register_operand" "r") @@ -325,8 +642,7 @@ (match_operand:SI 3 "some_operand" "r")) (match_operand:SI 4 "some_operand" "rIOKL"))))] "reload_in_progress" - "#" - [(set_attr "type" "iaddlog")]) + "#") (define_split [(set (match_operand:DI 0 "register_operand" "") @@ -351,8 +667,7 @@ (match_operand:DI 3 "some_operand" "r")) (match_operand:DI 4 "some_operand" "rIOKL")))] "reload_in_progress" - "#" - [(set_attr "type" "iaddlog")]) + "#") (define_split [(set (match_operand:DI 0 "register_operand" "=") @@ -370,23 +685,20 @@ [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_operand:SI 1 "reg_or_8bit_operand" "rI")))] "" - "subl $31,%1,%0" - [(set_attr "type" "iaddlog")]) + "subl $31,%1,%0") (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") (sign_extend:DI (neg:SI (match_operand:SI 1 "reg_or_8bit_operand" "rI"))))] "" - "subl $31,%1,%0" - [(set_attr "type" "iaddlog")]) + "subl $31,%1,%0") (define_insn "negdi2" [(set (match_operand:DI 0 "register_operand" "=r") (neg:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI")))] "" - "subq $31,%1,%0" - [(set_attr "type" "iaddlog")]) + "subq $31,%1,%0") (define_expand "subsi3" [(set (match_operand:SI 0 "register_operand" "") @@ -394,12 +706,11 @@ (match_operand:SI 2 "reg_or_8bit_operand" "")))] "" " -{ emit_insn (gen_rtx (SET, VOIDmode, gen_lowpart (DImode, operands[0]), - gen_rtx (MINUS, DImode, - gen_lowpart (DImode, operands[1]), - gen_lowpart (DImode, operands[2])))); +{ emit_insn (gen_rtx_SET (VOIDmode, gen_lowpart (DImode, operands[0]), + gen_rtx_MINUS (DImode, + gen_lowpart (DImode, operands[1]), + gen_lowpart (DImode, operands[2])))); DONE; - } ") (define_insn "" @@ -407,24 +718,21 @@ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ") (match_operand:SI 2 "reg_or_8bit_operand" "rI")))] "" - "subl %r1,%2,%0" - [(set_attr "type" "iaddlog")]) + "subl %r1,%2,%0") (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") (sign_extend:DI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ") (match_operand:SI 2 "reg_or_8bit_operand" "rI"))))] "" - "subl %r1,%2,%0" - [(set_attr "type" "iaddlog")]) + "subl %r1,%2,%0") (define_insn "subdi3" [(set (match_operand:DI 0 "register_operand" "=r") (minus:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") (match_operand:DI 2 "reg_or_8bit_operand" "rI")))] "" - "subq %r1,%2,%0" - [(set_attr "type" "iaddlog")]) + "subq %r1,%2,%0") (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") @@ -432,8 +740,7 @@ (match_operand:SI 2 "const48_operand" "I")) (match_operand:SI 3 "reg_or_8bit_operand" "rI")))] "" - "s%2subl %r1,%3,%0" - [(set_attr "type" "iaddlog")]) + "s%2subl %r1,%3,%0") (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") @@ -442,8 +749,7 @@ (match_operand:SI 2 "const48_operand" "I")) (match_operand:SI 3 "reg_or_8bit_operand" "rI"))))] "" - "s%2subl %r1,%3,%0" - [(set_attr "type" "iaddlog")]) + "s%2subl %r1,%3,%0") (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") @@ -451,8 +757,7 @@ (match_operand:DI 2 "const48_operand" "I")) (match_operand:DI 3 "reg_or_8bit_operand" "rI")))] "" - "s%2subq %r1,%3,%0" - [(set_attr "type" "iaddlog")]) + "s%2subq %r1,%3,%0") (define_insn "mulsi3" [(set (match_operand:SI 0 "register_operand" "=r") @@ -460,7 +765,8 @@ (match_operand:SI 2 "reg_or_0_operand" "rJ")))] "" "mull %r1,%r2,%0" - [(set_attr "type" "imull")]) + [(set_attr "type" "imul") + (set_attr "opsize" "si")]) (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") @@ -468,7 +774,8 @@ (match_operand:SI 2 "reg_or_0_operand" "rJ"))))] "" "mull %r1,%r2,%0" - [(set_attr "type" "imull")]) + [(set_attr "type" "imul") + (set_attr "opsize" "si")]) (define_insn "muldi3" [(set (match_operand:DI 0 "register_operand" "=r") @@ -476,7 +783,7 @@ (match_operand:DI 2 "reg_or_0_operand" "rJ")))] "" "mulq %r1,%r2,%0" - [(set_attr "type" "imulq")]) + [(set_attr "type" "imul")]) (define_insn "umuldi3_highpart" [(set (match_operand:DI 0 "register_operand" "=r") @@ -487,7 +794,8 @@ (const_int 64))))] "" "umulh %1,%2,%0" - [(set_attr "type" "imulq")]) + [(set_attr "type" "imul") + (set_attr "opsize" "udi")]) (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") @@ -498,61 +806,71 @@ (const_int 64))))] "" "umulh %1,%2,%0" - [(set_attr "type" "imulq")]) + [(set_attr "type" "imul") + (set_attr "opsize" "udi")]) ;; The divide and remainder operations always take their inputs from ;; r24 and r25, put their output in r27, and clobber r23 and r28. +;; ??? Force sign-extension here because some versions of OSF/1 don't +;; do the right thing if the inputs are not properly sign-extended. +;; But Linux, for instance, does not have this problem. Is it worth +;; the complication here to eliminate the sign extension? + (define_expand "divsi3" - [(set (reg:SI 24) (match_operand:SI 1 "input_operand" "")) - (set (reg:SI 25) (match_operand:SI 2 "input_operand" "")) - (parallel [(set (reg:SI 27) - (div:SI (reg:SI 24) - (reg:SI 25))) + [(set (reg:DI 24) + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" ""))) + (set (reg:DI 25) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" ""))) + (parallel [(set (reg:DI 27) + (sign_extend:DI (div:SI (reg:DI 24) (reg:DI 25)))) (clobber (reg:DI 23)) (clobber (reg:DI 28))]) (set (match_operand:SI 0 "general_operand" "") - (reg:SI 27))] - "" + (subreg:SI (reg:DI 27) 0))] + "!TARGET_OPEN_VMS" "") (define_expand "udivsi3" - [(set (reg:SI 24) (match_operand:SI 1 "input_operand" "")) - (set (reg:SI 25) (match_operand:SI 2 "input_operand" "")) - (parallel [(set (reg:SI 27) - (udiv:SI (reg:SI 24) - (reg:SI 25))) + [(set (reg:DI 24) + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" ""))) + (set (reg:DI 25) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" ""))) + (parallel [(set (reg:DI 27) + (sign_extend:DI (udiv:SI (reg:DI 24) (reg:DI 25)))) (clobber (reg:DI 23)) (clobber (reg:DI 28))]) (set (match_operand:SI 0 "general_operand" "") - (reg:SI 27))] - "" + (subreg:SI (reg:DI 27) 0))] + "!TARGET_OPEN_VMS" "") (define_expand "modsi3" - [(set (reg:SI 24) (match_operand:SI 1 "input_operand" "")) - (set (reg:SI 25) (match_operand:SI 2 "input_operand" "")) - (parallel [(set (reg:SI 27) - (mod:SI (reg:SI 24) - (reg:SI 25))) + [(set (reg:DI 24) + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" ""))) + (set (reg:DI 25) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" ""))) + (parallel [(set (reg:DI 27) + (sign_extend:DI (mod:SI (reg:DI 24) (reg:DI 25)))) (clobber (reg:DI 23)) (clobber (reg:DI 28))]) (set (match_operand:SI 0 "general_operand" "") - (reg:SI 27))] - "" + (subreg:SI (reg:DI 27) 0))] + "!TARGET_OPEN_VMS" "") (define_expand "umodsi3" - [(set (reg:SI 24) (match_operand:SI 1 "input_operand" "")) - (set (reg:SI 25) (match_operand:SI 2 "input_operand" "")) - (parallel [(set (reg:SI 27) - (umod:SI (reg:SI 24) - (reg:SI 25))) + [(set (reg:DI 24) + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" ""))) + (set (reg:DI 25) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" ""))) + (parallel [(set (reg:DI 27) + (sign_extend:DI (umod:SI (reg:DI 24) (reg:DI 25)))) (clobber (reg:DI 23)) (clobber (reg:DI 28))]) (set (match_operand:SI 0 "general_operand" "") - (reg:SI 27))] - "" + (subreg:SI (reg:DI 27) 0))] + "!TARGET_OPEN_VMS" "") (define_expand "divdi3" @@ -565,7 +883,7 @@ (clobber (reg:DI 28))]) (set (match_operand:DI 0 "general_operand" "") (reg:DI 27))] - "" + "!TARGET_OPEN_VMS" "") (define_expand "udivdi3" @@ -578,7 +896,7 @@ (clobber (reg:DI 28))]) (set (match_operand:DI 0 "general_operand" "") (reg:DI 27))] - "" + "!TARGET_OPEN_VMS" "") (define_expand "moddi3" @@ -591,7 +909,7 @@ (clobber (reg:DI 28))]) (set (match_operand:DI 0 "general_operand" "") (reg:DI 27))] - "" + "!TARGET_OPEN_VMS" "") (define_expand "umoddi3" @@ -604,18 +922,21 @@ (clobber (reg:DI 28))]) (set (match_operand:DI 0 "general_operand" "") (reg:DI 27))] - "" + "!TARGET_OPEN_VMS" "") +;; Lengths of 8 for ldq $t12,__divq($gp); jsr $t9,($t12),__divq as +;; expanded by the assembler. (define_insn "" - [(set (reg:SI 27) - (match_operator:SI 1 "divmod_operator" - [(reg:SI 24) (reg:SI 25)])) + [(set (reg:DI 27) + (sign_extend:DI (match_operator:SI 1 "divmod_operator" + [(reg:DI 24) (reg:DI 25)]))) (clobber (reg:DI 23)) (clobber (reg:DI 28))] - "" + "!TARGET_OPEN_VMS" "%E1 $24,$25,$27" - [(set_attr "type" "isubr")]) + [(set_attr "type" "jsr") + (set_attr "length" "8")]) (define_insn "" [(set (reg:DI 27) @@ -623,9 +944,10 @@ [(reg:DI 24) (reg:DI 25)])) (clobber (reg:DI 23)) (clobber (reg:DI 28))] - "" + "!TARGET_OPEN_VMS" "%E1 $24,$25,$27" - [(set_attr "type" "isubr")]) + [(set_attr "type" "jsr") + (set_attr "length" "8")]) ;; Next are the basic logical operations. These only exist in DImode. @@ -638,12 +960,12 @@ and %r1,%2,%0 bic %r1,%N2,%0 zapnot %r1,%m2,%0" - [(set_attr "type" "iaddlog,iaddlog,shiftcm")]) + [(set_attr "type" "ilog,ilog,shift")]) -;; There are times when we can split and AND into two AND insns. This occurs +;; There are times when we can split an AND into two AND insns. This occurs ;; when we can first clear any bytes and then clear anything else. For ;; example "I & 0xffff07" is "(I & 0xffffff) & 0xffffffffffffff07". -;; Only to this when running on 64-bit host since the computations are +;; Only do this when running on 64-bit host since the computations are ;; too messy otherwise. (define_split @@ -675,43 +997,103 @@ [(set (match_operand:HI 0 "register_operand" "=r") (zero_extend:HI (match_operand:QI 1 "register_operand" "r")))] "" - "zapnot %1,1,%0" - [(set_attr "type" "iaddlog")]) + "and %1,0xff,%0" + [(set_attr "type" "ilog")]) + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "TARGET_BWX" + "@ + and %1,0xff,%0 + ldbu %0,%1" + [(set_attr "type" "ilog,ild")]) -(define_insn "zero_extendqisi2" +(define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extend:SI (match_operand:QI 1 "register_operand" "r")))] + "! TARGET_BWX" + "and %1,0xff,%0" + [(set_attr "type" "ilog")]) + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:QI 1 "register_operand" "")))] "" - "zapnot %1,1,%0" - [(set_attr "type" "iaddlog")]) + "") -(define_insn "zero_extendqidi2" +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "TARGET_BWX" + "@ + and %1,0xff,%0 + ldbu %0,%1" + [(set_attr "type" "ilog,ild")]) + +(define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (match_operand:QI 1 "register_operand" "r")))] + "! TARGET_BWX" + "and %1,0xff,%0" + [(set_attr "type" "ilog")]) + +(define_expand "zero_extendqidi2" + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI (match_operand:QI 1 "register_operand" "")))] "" - "zapnot %1,1,%0" - [(set_attr "type" "iaddlog")]) + "") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] + "TARGET_BWX" + "@ + zapnot %1,3,%0 + ldwu %0,%1" + [(set_attr "type" "shift,ild")]) -(define_insn "zero_extendhisi2" +(define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extend:SI (match_operand:HI 1 "register_operand" "r")))] - "" + "! TARGET_BWX" "zapnot %1,3,%0" - [(set_attr "type" "iaddlog")]) + [(set_attr "type" "shift")]) + +(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:DI 0 "register_operand" "=r,r") + (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] + "TARGET_BWX" + "@ + zapnot %1,3,%0 + ldwu %0,%1" + [(set_attr "type" "shift,ild")]) -(define_insn "zero_extendhidi2" +(define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (match_operand:HI 1 "register_operand" "r")))] "" "zapnot %1,3,%0" - [(set_attr "type" "iaddlog")]) + [(set_attr "type" "shift")]) + +(define_expand "zero_extendhidi2" + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI (match_operand:HI 1 "register_operand" "")))] + "" + "") (define_insn "zero_extendsidi2" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (match_operand:SI 1 "register_operand" "r")))] "" "zapnot %1,15,%0" - [(set_attr "type" "iaddlog")]) + [(set_attr "type" "shift")]) (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") @@ -719,7 +1101,7 @@ (match_operand:DI 2 "reg_or_0_operand" "rJ")))] "" "bic %r2,%1,%0" - [(set_attr "type" "iaddlog")]) + [(set_attr "type" "ilog")]) (define_insn "iordi3" [(set (match_operand:DI 0 "register_operand" "=r,r") @@ -729,14 +1111,14 @@ "@ bis %r1,%2,%0 ornot %r1,%N2,%0" - [(set_attr "type" "iaddlog")]) + [(set_attr "type" "ilog")]) (define_insn "one_cmpldi2" [(set (match_operand:DI 0 "register_operand" "=r") (not:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI")))] "" "ornot $31,%1,%0" - [(set_attr "type" "iaddlog")]) + [(set_attr "type" "ilog")]) (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") @@ -744,7 +1126,7 @@ (match_operand:DI 2 "reg_or_0_operand" "rJ")))] "" "ornot %r2,%1,%0" - [(set_attr "type" "iaddlog")]) + [(set_attr "type" "ilog")]) (define_insn "xordi3" [(set (match_operand:DI 0 "register_operand" "=r,r") @@ -754,7 +1136,7 @@ "@ xor %r1,%2,%0 eqv %r1,%N2,%0" - [(set_attr "type" "iaddlog")]) + [(set_attr "type" "ilog")]) (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") @@ -762,14 +1144,40 @@ (match_operand:DI 2 "register_operand" "rI"))))] "" "eqv %r1,%2,%0" - [(set_attr "type" "iaddlog")]) + [(set_attr "type" "ilog")]) + +;; Handle the FFS insn if we support CIX. + +(define_expand "ffsdi2" + [(set (match_dup 2) + (unspec [(match_operand:DI 1 "register_operand" "")] 1)) + (set (match_dup 3) + (plus:DI (match_dup 2) (const_int 1))) + (set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (eq (match_dup 1) (const_int 0)) + (const_int 0) (match_dup 3)))] + "TARGET_CIX" + " +{ + operands[2] = gen_reg_rtx (DImode); + operands[3] = gen_reg_rtx (DImode); +}") + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec [(match_operand:DI 1 "register_operand" "r")] 1))] + "TARGET_CIX" + "cttz %1,%0" + ; ev6 calls all mvi and cttz/ctlz/popc class imisc, so just + ; reuse the existing type name. + [(set_attr "type" "mvi")]) ;; Next come the shifts and the various extract and insert operations. (define_insn "ashldi3" [(set (match_operand:DI 0 "register_operand" "=r,r") (ashift:DI (match_operand:DI 1 "reg_or_0_operand" "rJ,rJ") - (match_operand:DI 2 "reg_or_6bit_operand" "P,rI")))] + (match_operand:DI 2 "reg_or_6bit_operand" "P,rS")))] "" "* { @@ -782,9 +1190,11 @@ return \"s%P2addq %r1,0,%0\"; case 1: return \"sll %r1,%2,%0\"; + default: + abort(); } }" - [(set_attr "type" "iaddlog,shiftcm")]) + [(set_attr "type" "iadd,shift")]) ;; ??? The following pattern is made by combine, but earlier phases ;; (specifically flow) can't handle it. This occurs in jump.c. Deal @@ -803,224 +1213,469 @@ ;; else ;; return \"s%P2addl %r1,0,%0\"; ;; }" -;; [(set_attr "type" "iaddlog")]) +;; [(set_attr "type" "iadd")]) (define_insn "lshrdi3" [(set (match_operand:DI 0 "register_operand" "=r") (lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") - (match_operand:DI 2 "reg_or_6bit_operand" "rI")))] + (match_operand:DI 2 "reg_or_6bit_operand" "rS")))] "" - "srl %r1,%2,%0") + "srl %r1,%2,%0" + [(set_attr "type" "shift")]) (define_insn "ashrdi3" [(set (match_operand:DI 0 "register_operand" "=r") (ashiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") - (match_operand:DI 2 "reg_or_6bit_operand" "rI")))] + (match_operand:DI 2 "reg_or_6bit_operand" "rS")))] "" - "sra %r1,%2,%0") + "sra %r1,%2,%0" + [(set_attr "type" "shift")]) (define_expand "extendqihi2" [(set (match_dup 2) - (ashift:DI (match_operand:QI 1 "register_operand" "") + (ashift:DI (match_operand:QI 1 "some_operand" "") (const_int 56))) (set (match_operand:HI 0 "register_operand" "") (ashiftrt:DI (match_dup 2) (const_int 56)))] "" " -{ operands[0] = gen_lowpart (DImode, operands[0]); - operands[1] = gen_lowpart (DImode, operands[1]); +{ + if (TARGET_BWX) + { + emit_insn (gen_extendqihi2x (operands[0], + force_reg (QImode, operands[1]))); + DONE; + } + + /* If we have an unaligned MEM, extend to DImode (which we do + specially) and then copy to the result. */ + if (unaligned_memory_operand (operands[1], HImode)) + { + rtx temp = gen_reg_rtx (DImode); + + emit_insn (gen_extendqidi2 (temp, operands[1])); + emit_move_insn (operands[0], gen_lowpart (HImode, temp)); + DONE; + } + + operands[0] = gen_lowpart (DImode, operands[0]); + operands[1] = gen_lowpart (DImode, force_reg (QImode, operands[1])); operands[2] = gen_reg_rtx (DImode); }") +(define_insn "extendqidi2x" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI (match_operand:QI 1 "register_operand" "r")))] + "TARGET_BWX" + "sextb %1,%0" + [(set_attr "type" "shift")]) + +(define_insn "extendhidi2x" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI (match_operand:HI 1 "register_operand" "r")))] + "TARGET_BWX" + "sextw %1,%0" + [(set_attr "type" "shift")]) + +(define_insn "extendqisi2x" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))] + "TARGET_BWX" + "sextb %1,%0" + [(set_attr "type" "shift")]) + +(define_insn "extendhisi2x" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))] + "TARGET_BWX" + "sextw %1,%0" + [(set_attr "type" "shift")]) + +(define_insn "extendqihi2x" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))] + "TARGET_BWX" + "sextb %1,%0" + [(set_attr "type" "shift")]) + (define_expand "extendqisi2" [(set (match_dup 2) - (ashift:DI (match_operand:QI 1 "register_operand" "") + (ashift:DI (match_operand:QI 1 "some_operand" "") (const_int 56))) (set (match_operand:SI 0 "register_operand" "") (ashiftrt:DI (match_dup 2) (const_int 56)))] "" " -{ operands[0] = gen_lowpart (DImode, operands[0]); - operands[1] = gen_lowpart (DImode, operands[1]); +{ + if (TARGET_BWX) + { + emit_insn (gen_extendqisi2x (operands[0], + force_reg (QImode, operands[1]))); + DONE; + } + + /* If we have an unaligned MEM, extend to a DImode form of + the result (which we do specially). */ + if (unaligned_memory_operand (operands[1], QImode)) + { + rtx temp = gen_reg_rtx (DImode); + + emit_insn (gen_extendqidi2 (temp, operands[1])); + emit_move_insn (operands[0], gen_lowpart (SImode, temp)); + DONE; + } + + operands[0] = gen_lowpart (DImode, operands[0]); + operands[1] = gen_lowpart (DImode, force_reg (QImode, operands[1])); operands[2] = gen_reg_rtx (DImode); }") (define_expand "extendqidi2" [(set (match_dup 2) - (ashift:DI (match_operand:QI 1 "register_operand" "") + (ashift:DI (match_operand:QI 1 "some_operand" "") (const_int 56))) (set (match_operand:DI 0 "register_operand" "") (ashiftrt:DI (match_dup 2) (const_int 56)))] "" " -{ operands[1] = gen_lowpart (DImode, operands[1]); +{ + if (TARGET_BWX) + { + emit_insn (gen_extendqidi2x (operands[0], + force_reg (QImode, operands[1]))); + DONE; + } + + if (unaligned_memory_operand (operands[1], QImode)) + { + rtx seq + = gen_unaligned_extendqidi (operands[0], + get_unaligned_address (operands[1], 1)); + + alpha_set_memflags (seq, operands[1]); + emit_insn (seq); + DONE; + } + + operands[1] = gen_lowpart (DImode, force_reg (QImode, operands[1])); operands[2] = gen_reg_rtx (DImode); }") (define_expand "extendhisi2" [(set (match_dup 2) - (ashift:DI (match_operand:HI 1 "register_operand" "") + (ashift:DI (match_operand:HI 1 "some_operand" "") (const_int 48))) (set (match_operand:SI 0 "register_operand" "") (ashiftrt:DI (match_dup 2) (const_int 48)))] "" " -{ operands[0] = gen_lowpart (DImode, operands[0]); - operands[1] = gen_lowpart (DImode, operands[1]); +{ + if (TARGET_BWX) + { + emit_insn (gen_extendhisi2x (operands[0], + force_reg (HImode, operands[1]))); + DONE; + } + + /* If we have an unaligned MEM, extend to a DImode form of + the result (which we do specially). */ + if (unaligned_memory_operand (operands[1], HImode)) + { + rtx temp = gen_reg_rtx (DImode); + + emit_insn (gen_extendhidi2 (temp, operands[1])); + emit_move_insn (operands[0], gen_lowpart (SImode, temp)); + DONE; + } + + operands[0] = gen_lowpart (DImode, operands[0]); + operands[1] = gen_lowpart (DImode, force_reg (HImode, operands[1])); operands[2] = gen_reg_rtx (DImode); }") (define_expand "extendhidi2" [(set (match_dup 2) - (ashift:DI (match_operand:HI 1 "register_operand" "") + (ashift:DI (match_operand:HI 1 "some_operand" "") (const_int 48))) (set (match_operand:DI 0 "register_operand" "") (ashiftrt:DI (match_dup 2) (const_int 48)))] "" " -{ operands[1] = gen_lowpart (DImode, operands[1]); +{ + if (TARGET_BWX) + { + emit_insn (gen_extendhidi2x (operands[0], + force_reg (HImode, operands[1]))); + DONE; + } + + if (unaligned_memory_operand (operands[1], HImode)) + { + rtx seq + = gen_unaligned_extendhidi (operands[0], + get_unaligned_address (operands[1], 2)); + + alpha_set_memflags (seq, operands[1]); + emit_insn (seq); + DONE; + } + + operands[1] = gen_lowpart (DImode, force_reg (HImode, operands[1])); operands[2] = gen_reg_rtx (DImode); }") +;; Here's how we sign extend an unaligned byte and halfword. Doing this +;; as a pattern saves one instruction. The code is similar to that for +;; the unaligned loads (see below). +;; +;; Operand 1 is the address + 1 (+2 for HI), operand 0 is the result. +(define_expand "unaligned_extendqidi" + [(set (match_dup 2) (match_operand:DI 1 "address_operand" "")) + (set (match_dup 3) + (mem:DI (and:DI (plus:DI (match_dup 2) (const_int -1)) + (const_int -8)))) + (set (match_dup 4) + (ashift:DI (match_dup 3) + (minus:DI (const_int 56) + (ashift:DI + (and:DI (plus:DI (match_dup 2) (const_int -1)) + (const_int 7)) + (const_int 3))))) + (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0) + (ashiftrt:DI (match_dup 4) (const_int 56)))] + "" + " +{ operands[2] = gen_reg_rtx (DImode); + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); +}") + +(define_expand "unaligned_extendhidi" + [(set (match_dup 2) (match_operand:DI 1 "address_operand" "")) + (set (match_dup 3) + (mem:DI (and:DI (plus:DI (match_dup 2) (const_int -2)) + (const_int -8)))) + (set (match_dup 4) + (ashift:DI (match_dup 3) + (minus:DI (const_int 56) + (ashift:DI + (and:DI (plus:DI (match_dup 2) (const_int -1)) + (const_int 7)) + (const_int 3))))) + (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0) + (ashiftrt:DI (match_dup 4) (const_int 48)))] + "" + " +{ operands[2] = gen_reg_rtx (DImode); + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); +}") + (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") (match_operand:DI 2 "mode_width_operand" "n") (match_operand:DI 3 "mul8_operand" "I")))] "" - "ext%M2l %r1,%s3,%0") + "ext%M2l %r1,%s3,%0" + [(set_attr "type" "shift")]) -(define_insn "" +(define_insn "extxl" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") (match_operand:DI 2 "mode_width_operand" "n") (ashift:DI (match_operand:DI 3 "reg_or_8bit_operand" "rI") (const_int 3))))] "" - "ext%M2l %r1,%3,%0") + "ext%M2l %r1,%3,%0" + [(set_attr "type" "shift")]) -(define_insn "" +(define_insn "extqh" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI - (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") - (const_int 8) - (ashift:DI - (plus:DI - (match_operand:DI 2 "reg_or_8bit_operand" "rI") - (const_int -1)) - (const_int 3))) - (const_int 56)))] - "" - "extqh %r1,%2,%0") - -(define_insn "" + (match_operand:DI 1 "reg_or_0_operand" "rJ") + (minus:DI (const_int 56) + (ashift:DI + (and:DI + (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int -1)) + (const_int 7)) + (const_int 3)))))] + "" + "extqh %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extlh" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI - (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") - (const_int 16) - (ashift:DI - (plus:DI - (match_operand:DI 2 "reg_or_8bit_operand" "rI") - (const_int -2)) - (const_int 3))) - (const_int 48)))] - "" - "extwh %r1,%2,%0") - -(define_insn "" + (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (const_int 2147483647)) + (minus:DI (const_int 56) + (ashift:DI + (and:DI + (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int -1)) + (const_int 7)) + (const_int 3)))))] + "" + "extlh %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extwh" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI - (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") - (const_int 32) - (ashift:DI - (plus:DI - (match_operand:DI 2 "reg_or_8bit_operand" "rI") - (const_int -4)) - (const_int 3))) - (const_int 32)))] - "" - "extlh %r1,%2,%0") + (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (const_int 65535)) + (minus:DI (const_int 56) + (ashift:DI + (and:DI + (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int -1)) + (const_int 7)) + (const_int 3)))))] + "" + "extwh %r1,%2,%0" + [(set_attr "type" "shift")]) ;; This converts an extXl into an extXh with an appropriate adjustment ;; to the address calculation. -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (ashift:DI (zero_extract:DI (match_operand:DI 1 "register_operand" "") - (match_operand:DI 2 "mode_width_operand" "") - (ashift:DI (match_operand:DI 3 "" "") - (const_int 3))) - (match_operand:DI 4 "const_int_operand" ""))) - (clobber (match_operand:DI 5 "register_operand" ""))] - "INTVAL (operands[4]) == 64 - INTVAL (operands[2])" - [(set (match_dup 5) (match_dup 6)) - (set (match_dup 0) - (ashift:DI (zero_extract:DI (match_dup 1) (match_dup 2) - (ashift:DI (plus:DI (match_dup 5) - (match_dup 7)) - (const_int 3))) - (match_dup 4)))] - " -{ - operands[6] = plus_constant (operands[3], - INTVAL (operands[2]) / BITS_PER_UNIT); - operands[7] = GEN_INT (- INTVAL (operands[2]) / BITS_PER_UNIT); -}") +;;(define_split +;; [(set (match_operand:DI 0 "register_operand" "") +;; (ashift:DI (zero_extract:DI (match_operand:DI 1 "register_operand" "") +;; (match_operand:DI 2 "mode_width_operand" "") +;; (ashift:DI (match_operand:DI 3 "" "") +;; (const_int 3))) +;; (match_operand:DI 4 "const_int_operand" ""))) +;; (clobber (match_operand:DI 5 "register_operand" ""))] +;; "INTVAL (operands[4]) == 64 - INTVAL (operands[2])" +;; [(set (match_dup 5) (match_dup 6)) +;; (set (match_dup 0) +;; (ashift:DI (zero_extract:DI (match_dup 1) (match_dup 2) +;; (ashift:DI (plus:DI (match_dup 5) +;; (match_dup 7)) +;; (const_int 3))) +;; (match_dup 4)))] +;; " +;;{ +;; operands[6] = plus_constant (operands[3], +;; INTVAL (operands[2]) / BITS_PER_UNIT); +;; operands[7] = GEN_INT (- INTVAL (operands[2]) / BITS_PER_UNIT); +;;}") (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r")) (match_operand:DI 2 "mul8_operand" "I")))] "" - "insbl %1,%s2,%0") + "insbl %1,%s2,%0" + [(set_attr "type" "shift")]) (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r")) (match_operand:DI 2 "mul8_operand" "I")))] "" - "inswl %1,%s2,%0") + "inswl %1,%s2,%0" + [(set_attr "type" "shift")]) (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) (match_operand:DI 2 "mul8_operand" "I")))] "" - "insll %1,%s2,%0") + "insll %1,%s2,%0" + [(set_attr "type" "shift")]) -(define_insn "" +(define_insn "insbl" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r")) (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 3))))] "" - "insbl %1,%2,%0") + "insbl %1,%2,%0" + [(set_attr "type" "shift")]) -(define_insn "" +(define_insn "inswl" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r")) (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 3))))] "" - "inswl %1,%2,%0") + "inswl %1,%2,%0" + [(set_attr "type" "shift")]) -(define_insn "" +(define_insn "insll" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") (const_int 3))))] "" - "insll %1,%2,%0") + "insll %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "insql" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (match_operand:DI 1 "register_operand" "r") + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3))))] + "" + "insql %1,%2,%0" + [(set_attr "type" "shift")]) + +;; Combine has this sometimes habit of moving the and outside of the +;; shift, making life more interesting. + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mul8_operand" "I")) + (match_operand:DI 3 "immediate_operand" "i")))] + "HOST_BITS_PER_WIDE_INT == 64 + && GET_CODE (operands[3]) == CONST_INT + && (((unsigned HOST_WIDE_INT) 0xff << INTVAL (operands[2]) + == INTVAL (operands[3])) + || ((unsigned HOST_WIDE_INT) 0xffff << INTVAL (operands[2]) + == INTVAL (operands[3])) + || ((unsigned HOST_WIDE_INT) 0xffffffff << INTVAL (operands[2]) + == INTVAL (operands[3])))" + "* +{ +#if HOST_BITS_PER_WIDE_INT == 64 + if ((unsigned HOST_WIDE_INT) 0xff << INTVAL (operands[2]) + == INTVAL (operands[3])) + return \"insbl %1,%s2,%0\"; + if ((unsigned HOST_WIDE_INT) 0xffff << INTVAL (operands[2]) + == INTVAL (operands[3])) + return \"inswl %1,%s2,%0\"; + if ((unsigned HOST_WIDE_INT) 0xffffffff << INTVAL (operands[2]) + == INTVAL (operands[3])) + return \"insll %1,%s2,%0\"; +#endif + abort(); +}" + [(set_attr "type" "shift")]) ;; We do not include the insXh insns because they are complex to express ;; and it does not appear that we would ever want to generate them. +;; +;; Since we need them for block moves, though, cop out and use unspec. -(define_insn "" +(define_insn "insxh" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec [(match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mode_width_operand" "n") + (match_operand:DI 3 "reg_or_8bit_operand" "rI")] 2))] + "" + "ins%M2h %1,%3,%0" + [(set_attr "type" "shift")]) + +(define_insn "mskxl" [(set (match_operand:DI 0 "register_operand" "=r") (and:DI (not:DI (ashift:DI (match_operand:DI 2 "mode_mask_operand" "n") @@ -1029,10 +1684,22 @@ (const_int 3)))) (match_operand:DI 1 "reg_or_0_operand" "rJ")))] "" - "msk%U2l %r1,%3,%0") + "msk%U2l %r1,%3,%0" + [(set_attr "type" "shift")]) -;; We do not include the mskXh insns because it does not appear we would ever -;; generate one. +;; We do not include the mskXh insns because it does not appear we would +;; ever generate one. +;; +;; Again, we do for block moves and we use unspec again. + +(define_insn "mskxh" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec [(match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mode_width_operand" "n") + (match_operand:DI 3 "reg_or_8bit_operand" "rI")] 3))] + "" + "msk%M2h %1,%3,%0" + [(set_attr "type" "shift")]) ;; Floating-point operations. All the double-precision insns can extend ;; from single, so indicate that. The exception are the ones that simply @@ -1043,53 +1710,74 @@ (abs:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))] "TARGET_FP" "cpys $f31,%R1,%0" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fcpys")]) (define_insn "absdf2" [(set (match_operand:DF 0 "register_operand" "=f") (abs:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))] "TARGET_FP" "cpys $f31,%R1,%0" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fcpys")]) (define_insn "negsf2" [(set (match_operand:SF 0 "register_operand" "=f") (neg:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))] "TARGET_FP" "cpysn %R1,%R1,%0" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fadd")]) (define_insn "negdf2" [(set (match_operand:DF 0 "register_operand" "=f") (neg:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))] "TARGET_FP" "cpysn %R1,%R1,%0" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fadd")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=&f") + (plus:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG") + (match_operand:SF 2 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "add%,%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "addsf3" [(set (match_operand:SF 0 "register_operand" "=f") (plus:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG") (match_operand:SF 2 "reg_or_fp0_operand" "fG")))] "TARGET_FP" - "adds %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "add%,%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=&f") + (plus:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG") + (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "add%-%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "adddf3" [(set (match_operand:DF 0 "register_operand" "=f") (plus:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG") (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] "TARGET_FP" - "addt %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "add%-%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (plus:DF (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG")) (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] - "TARGET_FP" - "addt %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "add%-%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") @@ -1097,120 +1785,344 @@ (match_operand:SF 1 "reg_or_fp0_operand" "%fG")) (float_extend:DF (match_operand:SF 2 "reg_or_fp0_operand" "fG"))))] + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "add%-%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +;; Define conversion operators between DFmode and SImode, using the cvtql +;; instruction. To allow combine et al to do useful things, we keep the +;; operation as a unit until after reload, at which point we split the +;; instructions. + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (fix:SI (match_operand:DF 1 "reg_or_fp0_operand" ""))) + (clobber (match_scratch:DI 2 ""))] + "TARGET_FP && reload_completed" + [(set (match_dup 2) (fix:DI (match_dup 1))) + (set (match_dup 0) (unspec:SI [(match_dup 2)] 5))] + "") + +;; Due to issues with CLASS_CANNOT_CHANGE_SIZE, we cannot use a subreg here. +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (fix:SI (match_operand:DF 1 "reg_or_fp0_operand" "")))] + "TARGET_FP && reload_completed" + [(set (match_dup 2) (fix:DI (match_dup 1))) + (set (match_dup 0) (unspec:SI [(match_dup 2)] 5))] + "operands[2] = gen_rtx_REG (DImode, REGNO (operands[0]));") + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=f") + (unspec:SI [(match_operand:DI 1 "reg_or_fp0_operand" "fG")] 5))] "TARGET_FP" - "addt %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "cvtql%` %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "fix_truncdfsi2_tp" + [(set (match_operand:SI 0 "register_operand" "=&f") + (fix:SI (match_operand:DF 1 "reg_or_fp0_operand" "fG"))) + (clobber (match_scratch:DI 2 "=&f"))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "#" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=f") + (fix:SI (match_operand:DF 1 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "#" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_expand "fix_truncdfsi2" + [(set (match_operand:SI 0 "register_operand" "=f") + (fix:SI (match_operand:DF 1 "reg_or_fp0_operand" "fG")))] + "TARGET_FP" + "{ if (alpha_tp == ALPHA_TP_INSN) + { emit_insn(gen_fix_truncdfsi2_tp(operands[0], operands[1])); DONE; } + }") + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=&f") + (fix:DI (match_operand:DF 1 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "cvt%-q%(c %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "fix_truncdfdi2" [(set (match_operand:DI 0 "register_operand" "=f") (fix:DI (match_operand:DF 1 "reg_or_fp0_operand" "fG")))] "TARGET_FP" - "cvttqc %R1,%0" - [(set_attr "type" "fpop")]) + "cvt%-q%(c %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +;; Likewise between SFmode and SImode. + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (fix:SI (float_extend:DF + (match_operand:SF 1 "reg_or_fp0_operand" "")))) + (clobber (match_scratch:DI 2 ""))] + "TARGET_FP && reload_completed" + [(set (match_dup 2) (fix:DI (float_extend:DF (match_dup 1)))) + (set (match_dup 0) (unspec:SI [(match_dup 2)] 5))] + "") + +;; Due to issues with CLASS_CANNOT_CHANGE_SIZE, we cannot use a subreg here. +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (fix:SI (float_extend:DF + (match_operand:SF 1 "reg_or_fp0_operand" ""))))] + "TARGET_FP && reload_completed" + [(set (match_dup 2) (fix:DI (float_extend:DF (match_dup 1)))) + (set (match_dup 0) (unspec:SI [(match_dup 2)] 5))] + "operands[2] = gen_rtx_REG (DImode, REGNO (operands[0]));") + +(define_insn "fix_truncsfsi2_tp" + [(set (match_operand:SI 0 "register_operand" "=&f") + (fix:SI (float_extend:DF + (match_operand:SF 1 "reg_or_fp0_operand" "fG")))) + (clobber (match_scratch:DI 2 "=&f"))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "#" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:SI 0 "register_operand" "=f") + (fix:SI (float_extend:DF + (match_operand:SF 1 "reg_or_fp0_operand" "fG"))))] + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "#" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_expand "fix_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "=f") + (fix:SI (float_extend:DF + (match_operand:SF 1 "reg_or_fp0_operand" "fG"))))] + "TARGET_FP" + "{ if (alpha_tp == ALPHA_TP_INSN) + { emit_insn(gen_fix_truncsfsi2_tp(operands[0], operands[1])); DONE; } + }") + +(define_insn "" + [(set (match_operand:DI 0 "register_operand" "=&f") + (fix:DI (float_extend:DF + (match_operand:SF 1 "reg_or_fp0_operand" "fG"))))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "cvt%-q%(c %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "fix_truncsfdi2" [(set (match_operand:DI 0 "register_operand" "=f") (fix:DI (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG"))))] "TARGET_FP" - "cvttqc %R1,%0" - [(set_attr "type" "fpop")]) + "cvt%-q%(c %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=&f") + (float:SF (match_operand:DI 1 "register_operand" "f")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "cvtq%,%+%& %1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "floatdisf2" [(set (match_operand:SF 0 "register_operand" "=f") (float:SF (match_operand:DI 1 "register_operand" "f")))] "TARGET_FP" - "cvtqs %1,%0" - [(set_attr "type" "fpop")]) + "cvtq%,%+%& %1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=&f") + (float:DF (match_operand:DI 1 "register_operand" "f")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "cvtq%-%+%& %1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "floatdidf2" [(set (match_operand:DF 0 "register_operand" "=f") (float:DF (match_operand:DI 1 "register_operand" "f")))] "TARGET_FP" - "cvtqt %1,%0" - [(set_attr "type" "fpop")]) + "cvtq%-%+%& %1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) -(define_insn "extendsfdf2" - [(set (match_operand:DF 0 "register_operand" "=f,f") - (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,m")))] +(define_expand "extendsfdf2" + [(use (match_operand:DF 0 "register_operand" "")) + (use (match_operand:SF 1 "nonimmediate_operand" ""))] "TARGET_FP" +" +{ + if (alpha_tp == ALPHA_TP_INSN) + emit_insn (gen_extendsfdf2_tp (operands[0], + force_reg (SFmode, operands[1]))); + else + emit_insn (gen_extendsfdf2_no_tp (operands[0], operands[1])); + + DONE; +}") +;; FIXME +(define_insn "extendsfdf2_tp" + [(set (match_operand:DF 0 "register_operand" "=&f") + (float_extend:DF (match_operand:SF 1 "register_operand" "f")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "cvtsts %1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "extendsfdf2_no_tp" + [(set (match_operand:DF 0 "register_operand" "=f,f,m") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,m,f")))] + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" "@ - addt $f31,%1,%0 - lds %0,%1" - [(set_attr "type" "fpop,ld")]) + cpys %1,%1,%0 + ld%, %0,%1 + st%- %1,%0" + [(set_attr "type" "fcpys,fld,fst") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=&f") + (float_truncate:SF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "cvt%-%,%)%& %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "truncdfsf2" [(set (match_operand:SF 0 "register_operand" "=f") (float_truncate:SF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))] "TARGET_FP" - "cvtts %R1,%0" - [(set_attr "type" "fpop")]) + "cvt%-%,%)%& %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=&f") + (div:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG") + (match_operand:SF 2 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "div%,%)%& %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "opsize" "si") + (set_attr "trap" "yes")]) (define_insn "divsf3" [(set (match_operand:SF 0 "register_operand" "=f") (div:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG") (match_operand:SF 2 "reg_or_fp0_operand" "fG")))] "TARGET_FP" - "divs %R1,%R2,%0" - [(set_attr "type" "fdivs")]) + "div%,%)%& %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "opsize" "si") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=&f") + (div:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG") + (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "div%-%)%& %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "trap" "yes")]) (define_insn "divdf3" [(set (match_operand:DF 0 "register_operand" "=f") (div:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG") (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] "TARGET_FP" - "divt %R1,%R2,%0" - [(set_attr "type" "fdivt")]) + "div%-%)%& %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (div:DF (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG")) (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] - "TARGET_FP" - "divt %R1,%R2,%0" - [(set_attr "type" "fdivt")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "div%-%)%& %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (div:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG") (float_extend:DF (match_operand:SF 2 "reg_or_fp0_operand" "fG"))))] - "TARGET_FP" - "divt %R1,%R2,%0" - [(set_attr "type" "fdivt")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "div%-%)%& %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (div:DF (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG")) (float_extend:DF (match_operand:SF 2 "reg_or_fp0_operand" "fG"))))] - "TARGET_FP" - "divt %R1,%R2,%0" - [(set_attr "type" "fdivt")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "div%-%)%& %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=&f") + (mult:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG") + (match_operand:SF 2 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "mul%,%)%& %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes")]) (define_insn "mulsf3" [(set (match_operand:SF 0 "register_operand" "=f") (mult:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG") (match_operand:SF 2 "reg_or_fp0_operand" "fG")))] "TARGET_FP" - "muls %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "mul%,%)%& %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=&f") + (mult:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG") + (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "mul%-%)%& %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes")]) (define_insn "muldf3" [(set (match_operand:DF 0 "register_operand" "=f") (mult:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG") (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] "TARGET_FP" - "mult %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "mul%-%)%& %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (mult:DF (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG")) (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] - "TARGET_FP" - "mult %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "mul%-%)%& %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") @@ -1218,43 +2130,66 @@ (match_operand:SF 1 "reg_or_fp0_operand" "%fG")) (float_extend:DF (match_operand:SF 2 "reg_or_fp0_operand" "fG"))))] - "TARGET_FP" - "mult %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "mul%-%)%& %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=&f") + (minus:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG") + (match_operand:SF 2 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "sub%,%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "subsf3" [(set (match_operand:SF 0 "register_operand" "=f") (minus:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG") (match_operand:SF 2 "reg_or_fp0_operand" "fG")))] "TARGET_FP" - "subs %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "sub%,%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=&f") + (minus:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG") + (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "sub%-%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "subdf3" [(set (match_operand:DF 0 "register_operand" "=f") (minus:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG") (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] "TARGET_FP" - "subt %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "sub%-%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (minus:DF (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG")) (match_operand:DF 2 "reg_or_fp0_operand" "fG")))] - "TARGET_FP" - "subt %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "sub%-%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (minus:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG") (float_extend:DF (match_operand:SF 2 "reg_or_fp0_operand" "fG"))))] - "TARGET_FP" - "subt %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "sub%-%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") @@ -1262,9 +2197,44 @@ (match_operand:SF 1 "reg_or_fp0_operand" "fG")) (float_extend:DF (match_operand:SF 2 "reg_or_fp0_operand" "fG"))))] - "TARGET_FP" - "subt %R1,%R2,%0" - [(set_attr "type" "fpop")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "sub%-%)%& %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:SF 0 "register_operand" "=&f") + (sqrt:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && TARGET_CIX && alpha_tp == ALPHA_TP_INSN" + "sqrt%,%)%& %R1,%0" + [(set_attr "type" "fsqrt") + (set_attr "opsize" "si") + (set_attr "trap" "yes")]) + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (sqrt:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && TARGET_CIX" + "sqrt%,%)%& %R1,%0" + [(set_attr "type" "fsqrt") + (set_attr "opsize" "si") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=&f") + (sqrt:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && TARGET_CIX && alpha_tp == ALPHA_TP_INSN" + "sqrt%-%)%& %R1,%0" + [(set_attr "type" "fsqrt") + (set_attr "trap" "yes")]) + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (sqrt:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))] + "TARGET_FP && TARGET_CIX" + "sqrt%-%)%& %1,%0" + [(set_attr "type" "fsqrt") + (set_attr "trap" "yes")]) ;; Next are all the integer comparisons, and conditional moves and branches ;; and some of the related define_expand's and define_split's. @@ -1278,31 +2248,13 @@ "cmp%C1 %r2,%3,%0" [(set_attr "type" "icmp")]) -;; There are three important special-case that don't fit the above pattern -;; but which we want to handle here. - -(define_insn "" - [(set (match_operand:DI 0 "register_operand" "=r") - (ne:DI (match_operand:DI 1 "register_operand" "r") - (const_int 0)))] - "" - "cmpult $31,%1,%0" - [(set_attr "type" "icmp")]) - (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r") - (gt:DI (match_operand:DI 1 "register_operand" "r") - (const_int 0)))] + (match_operator:DI 1 "alpha_swapped_comparison_operator" + [(match_operand:DI 2 "reg_or_8bit_operand" "rI") + (match_operand:DI 3 "reg_or_0_operand" "rJ")]))] "" - "cmplt $31,%1,%0" - [(set_attr "type" "icmp")]) - -(define_insn "" - [(set (match_operand:DI 0 "register_operand" "=r") - (ge:DI (match_operand:DI 1 "register_operand" "r") - (const_int 0)))] - "" - "cmple $31,%1,%0" + "cmp%c1 %r3,%2,%0" [(set_attr "type" "icmp")]) ;; This pattern exists so conditional moves of SImode values are handled. @@ -1321,7 +2273,8 @@ cmov%C2 %r3,%1,%0 cmov%D2 %r3,%5,%0 cmov%c2 %r4,%1,%0 - cmov%d2 %r4,%5,%0") + cmov%d2 %r4,%5,%0" + [(set_attr "type" "icmov")]) (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r,r,r,r") @@ -1336,7 +2289,8 @@ cmov%C2 %r3,%1,%0 cmov%D2 %r3,%5,%0 cmov%c2 %r4,%1,%0 - cmov%d2 %r4,%5,%0") + cmov%d2 %r4,%5,%0" + [(set_attr "type" "icmov")]) (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r,r") @@ -1350,7 +2304,8 @@ "" "@ cmovlbc %r2,%1,%0 - cmovlbs %r2,%3,%0") + cmovlbs %r2,%3,%0" + [(set_attr "type" "icmov")]) (define_insn "" [(set (match_operand:DI 0 "register_operand" "=r,r") @@ -1364,7 +2319,8 @@ "" "@ cmovlbs %r2,%1,%0 - cmovlbc %r2,%3,%0") + cmovlbc %r2,%3,%0" + [(set_attr "type" "icmov")]) ;; This form is added since combine thinks that an IF_THEN_ELSE with both ;; arms constant is a single insn, so it won't try to form it if combine @@ -1382,7 +2338,9 @@ (match_dup 0))) (clobber (match_scratch:DI 4 "=&r"))] "" - "addq %0,%1,%4\;cmov%C2 %r3,%4,%0") + "addq %0,%1,%4\;cmov%C2 %r3,%4,%0" + [(set_attr "type" "icmov") + (set_attr "length" "8")]) (define_split [(set (match_operand:DI 0 "register_operand" "") @@ -1500,6 +2458,70 @@ (match_dup 0) (match_dup 1)))] "") +(define_insn "sminqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (smin:SI (match_operand:QI 1 "reg_or_0_operand" "%rJ") + (match_operand:QI 2 "reg_or_8bit_operand" "rI")))] + "TARGET_MAX" + "minsb8 %r1,%2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "uminqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (umin:SI (match_operand:QI 1 "reg_or_0_operand" "%rJ") + (match_operand:QI 2 "reg_or_8bit_operand" "rI")))] + "TARGET_MAX" + "minub8 %r1,%2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "smaxqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (smax:SI (match_operand:QI 1 "reg_or_0_operand" "%rJ") + (match_operand:QI 2 "reg_or_8bit_operand" "rI")))] + "TARGET_MAX" + "maxsb8 %r1,%2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "umaxqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (umax:SI (match_operand:QI 1 "reg_or_0_operand" "%rJ") + (match_operand:QI 2 "reg_or_8bit_operand" "rI")))] + "TARGET_MAX" + "maxub8 %r1,%2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "sminhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (smin:SI (match_operand:HI 1 "reg_or_0_operand" "%rJ") + (match_operand:HI 2 "reg_or_8bit_operand" "rI")))] + "TARGET_MAX" + "minsw4 %r1,%2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "uminhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (umin:SI (match_operand:HI 1 "reg_or_0_operand" "%rJ") + (match_operand:HI 2 "reg_or_8bit_operand" "rI")))] + "TARGET_MAX" + "minuw4 %r1,%2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "smaxhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (smax:SI (match_operand:HI 1 "reg_or_0_operand" "%rJ") + (match_operand:HI 2 "reg_or_8bit_operand" "rI")))] + "TARGET_MAX" + "maxsw4 %r1,%2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "umaxhi3" + [(set (match_operand:HI 0 "register_operand" "=r") + (umax:SI (match_operand:HI 1 "reg_or_0_operand" "%rJ") + (match_operand:HI 2 "reg_or_8bit_operand" "rI")))] + "TARGET_MAX" + "maxuw4 %r1,%2,%0" + [(set_attr "type" "shift")]) + (define_expand "smaxdi3" [(set (match_dup 3) (le:DI (match_operand:DI 1 "reg_or_0_operand" "") @@ -1528,7 +2550,8 @@ (smax:DI (match_operand:DI 1 "register_operand" "0") (const_int 0)))] "" - "cmovlt %0,0,%0") + "cmovlt %0,0,%0" + [(set_attr "type" "icmov")]) (define_expand "smindi3" [(set (match_dup 3) @@ -1558,7 +2581,8 @@ (smin:DI (match_operand:DI 1 "register_operand" "0") (const_int 0)))] "" - "cmovgt %0,0,%0") + "cmovgt %0,0,%0" + [(set_attr "type" "icmov")]) (define_expand "umaxdi3" [(set (match_dup 3) @@ -1621,6 +2645,18 @@ (define_insn "" [(set (pc) (if_then_else + (match_operator 1 "signed_comparison_operator" + [(const_int 0) + (match_operand:DI 2 "register_operand" "r")]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "b%c1 %2,%0" + [(set_attr "type" "ibr")]) + +(define_insn "" + [(set (pc) + (if_then_else (ne (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") (const_int 1) (const_int 0)) @@ -1674,13 +2710,35 @@ ;; to DFmode. (define_insn "" + [(set (match_operand:DF 0 "register_operand" "=&f") + (match_operator:DF 1 "alpha_comparison_operator" + [(match_operand:DF 2 "reg_or_fp0_operand" "fG") + (match_operand:DF 3 "reg_or_fp0_operand" "fG")]))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "cmp%-%C1%' %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") (match_operator:DF 1 "alpha_comparison_operator" [(match_operand:DF 2 "reg_or_fp0_operand" "fG") (match_operand:DF 3 "reg_or_fp0_operand" "fG")]))] - "TARGET_FP" - "cmpt%C1 %R2,%R3,%0" - [(set_attr "type" "fpop")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "cmp%-%C1%' %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=&f") + (match_operator:DF 1 "alpha_comparison_operator" + [(float_extend:DF + (match_operand:SF 2 "reg_or_fp0_operand" "fG")) + (match_operand:DF 3 "reg_or_fp0_operand" "fG")]))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "cmp%-%C1%' %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") @@ -1688,9 +2746,21 @@ [(float_extend:DF (match_operand:SF 2 "reg_or_fp0_operand" "fG")) (match_operand:DF 3 "reg_or_fp0_operand" "fG")]))] - "TARGET_FP" - "cmpt%C1 %R2,%R3,%0" - [(set_attr "type" "fpop")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "cmp%-%C1%' %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=&f") + (match_operator:DF 1 "alpha_comparison_operator" + [(match_operand:DF 2 "reg_or_fp0_operand" "fG") + (float_extend:DF + (match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "cmp%-%C1%' %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") @@ -1698,9 +2768,22 @@ [(match_operand:DF 2 "reg_or_fp0_operand" "fG") (float_extend:DF (match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))] - "TARGET_FP" - "cmpt%C1 %R2,%R3,%0" - [(set_attr "type" "fpop")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "cmp%-%C1%' %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "" + [(set (match_operand:DF 0 "register_operand" "=&f") + (match_operator:DF 1 "alpha_comparison_operator" + [(float_extend:DF + (match_operand:SF 2 "reg_or_fp0_operand" "fG")) + (float_extend:DF + (match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))] + "TARGET_FP && alpha_tp == ALPHA_TP_INSN" + "cmp%-%C1%' %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f") @@ -1709,9 +2792,10 @@ (match_operand:SF 2 "reg_or_fp0_operand" "fG")) (float_extend:DF (match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))] - "TARGET_FP" - "cmpt%C1 %R2,%R3,%0" - [(set_attr "type" "fpop")]) + "TARGET_FP && alpha_tp != ALPHA_TP_INSN" + "cmp%-%C1%' %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f,f") @@ -1725,7 +2809,7 @@ "@ fcmov%C3 %R4,%R1,%0 fcmov%D3 %R4,%R5,%0" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fcmov")]) (define_insn "" [(set (match_operand:SF 0 "register_operand" "=f,f") @@ -1739,21 +2823,21 @@ "@ fcmov%C3 %R4,%R1,%0 fcmov%D3 %R4,%R5,%0" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fcmov")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f,f") (if_then_else:DF (match_operator 3 "signed_comparison_operator" - [(match_operand:DF 1 "reg_or_fp0_operand" "fG,fG") + [(match_operand:DF 4 "reg_or_fp0_operand" "fG,fG") (match_operand:DF 2 "fp0_operand" "G,G")]) - (float_extend:DF (match_operand:SF 4 "reg_or_fp0_operand" "fG,0")) + (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG,0")) (match_operand:DF 5 "reg_or_fp0_operand" "0,fG")))] "TARGET_FP" "@ fcmov%C3 %R4,%R1,%0 fcmov%D3 %R4,%R5,%0" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fcmov")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f,f") @@ -1768,7 +2852,7 @@ "@ fcmov%C3 %R4,%R1,%0 fcmov%D3 %R4,%R5,%0" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fcmov")]) (define_insn "" [(set (match_operand:SF 0 "register_operand" "=f,f") @@ -1783,7 +2867,7 @@ "@ fcmov%C3 %R4,%R1,%0 fcmov%D3 %R4,%R5,%0" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fcmov")]) (define_insn "" [(set (match_operand:DF 0 "register_operand" "=f,f") @@ -1798,7 +2882,7 @@ "@ fcmov%C3 %R4,%R1,%0 fcmov%D3 %R4,%R5,%0" - [(set_attr "type" "fpop")]) + [(set_attr "type" "fcmov")]) (define_expand "maxdf3" [(set (match_dup 3) @@ -1905,198 +2989,84 @@ }") (define_expand "beq" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - enum machine_mode mode; - enum rtx_code compare_code, branch_code; - - if (alpha_compare_fp_p) - mode = DFmode, compare_code = EQ, branch_code = NE; - else - { - mode = DImode, compare_code = MINUS, branch_code = EQ; - if (GET_CODE (alpha_compare_op1) == CONST_INT) - { - compare_code = PLUS; - alpha_compare_op1 = GEN_INT (- INTVAL (alpha_compare_op1)); - } - } - - operands[1] = gen_reg_rtx (mode); - operands[2] = gen_rtx (compare_code, mode, - alpha_compare_op0, alpha_compare_op1); - operands[3] = gen_rtx (branch_code, VOIDmode, - operands[1], CONST0_RTX (mode)); -}") + "{ operands[1] = alpha_emit_conditional_branch (EQ); }") (define_expand "bne" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - enum machine_mode mode; - enum rtx_code compare_code, branch_code; - - if (alpha_compare_fp_p) - mode = DFmode, compare_code = EQ, branch_code = EQ; - else - { - mode = DImode, compare_code = MINUS, branch_code = NE; - if (GET_CODE (alpha_compare_op1) == CONST_INT) - { - compare_code = PLUS; - alpha_compare_op1 = GEN_INT (- INTVAL (alpha_compare_op1)); - } - } - - operands[1] = gen_reg_rtx (mode); - operands[2] = gen_rtx (compare_code, mode, - alpha_compare_op0, alpha_compare_op1); - operands[3] = gen_rtx (branch_code, VOIDmode, - operands[1], CONST0_RTX (mode)); -}") + "{ operands[1] = alpha_emit_conditional_branch (NE); }") (define_expand "blt" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - enum machine_mode mode = alpha_compare_fp_p ? DFmode : DImode; - operands[1] = gen_reg_rtx (mode); - operands[2] = gen_rtx (LT, mode, alpha_compare_op0, alpha_compare_op1); - operands[3] = gen_rtx (NE, VOIDmode, operands[1], CONST0_RTX (mode)); -}") + "{ operands[1] = alpha_emit_conditional_branch (LT); }") (define_expand "ble" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - enum machine_mode mode = alpha_compare_fp_p ? DFmode : DImode; - operands[1] = gen_reg_rtx (mode); - operands[2] = gen_rtx (LE, mode, alpha_compare_op0, alpha_compare_op1); - operands[3] = gen_rtx (NE, VOIDmode, operands[1], CONST0_RTX (mode)); -}") + "{ operands[1] = alpha_emit_conditional_branch (LE); }") (define_expand "bgt" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - if (alpha_compare_fp_p) - { - operands[1] = gen_reg_rtx (DFmode); - operands[2] = gen_rtx (LT, DFmode, alpha_compare_op1, alpha_compare_op0); - operands[3] = gen_rtx (NE, VOIDmode, operands[1], CONST0_RTX (DFmode)); - } - else - { - operands[1] = gen_reg_rtx (DImode); - operands[2] = gen_rtx (LE, DImode, alpha_compare_op0, alpha_compare_op1); - operands[3] = gen_rtx (EQ, VOIDmode, operands[1], const0_rtx); - } -}") + "{ operands[1] = alpha_emit_conditional_branch (GT); }") (define_expand "bge" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - if (alpha_compare_fp_p) - { - operands[1] = gen_reg_rtx (DFmode); - operands[2] = gen_rtx (LE, DFmode, alpha_compare_op1, alpha_compare_op0); - operands[3] = gen_rtx (NE, VOIDmode, operands[1], CONST0_RTX (DFmode)); - } - else - { - operands[1] = gen_reg_rtx (DImode); - operands[2] = gen_rtx (LT, DImode, alpha_compare_op0, alpha_compare_op1); - operands[3] = gen_rtx (EQ, VOIDmode, operands[1], const0_rtx); - } -}") + "{ operands[1] = alpha_emit_conditional_branch (GE); }") (define_expand "bltu" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - operands[1] = gen_reg_rtx (DImode); - operands[2] = gen_rtx (LTU, DImode, alpha_compare_op0, alpha_compare_op1); - operands[3] = gen_rtx (NE, VOIDmode, operands[1], const0_rtx); -}") + "{ operands[1] = alpha_emit_conditional_branch (LTU); }") (define_expand "bleu" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - operands[1] = gen_reg_rtx (DImode); - operands[2] = gen_rtx (LEU, DImode, alpha_compare_op0, alpha_compare_op1); - operands[3] = gen_rtx (NE, VOIDmode, operands[1], const0_rtx); -}") + "{ operands[1] = alpha_emit_conditional_branch (LEU); }") (define_expand "bgtu" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - operands[1] = gen_reg_rtx (DImode); - operands[2] = gen_rtx (LEU, DImode, alpha_compare_op0, alpha_compare_op1); - operands[3] = gen_rtx (EQ, VOIDmode, operands[1], const0_rtx); -}") + "{ operands[1] = alpha_emit_conditional_branch (GTU); }") (define_expand "bgeu" - [(set (match_dup 1) (match_dup 2)) - (set (pc) - (if_then_else (match_dup 3) + [(set (pc) + (if_then_else (match_dup 1) (label_ref (match_operand 0 "" "")) (pc)))] "" - " -{ - operands[1] = gen_reg_rtx (DImode); - operands[2] = gen_rtx (LTU, DImode, alpha_compare_op0, alpha_compare_op1); - operands[3] = gen_rtx (EQ, VOIDmode, operands[1], const0_rtx); -}") + "{ operands[1] = alpha_emit_conditional_branch (GEU); }") (define_expand "seq" [(set (match_operand:DI 0 "register_operand" "") @@ -2107,7 +3077,7 @@ if (alpha_compare_fp_p) FAIL; - operands[1] = gen_rtx (EQ, DImode, alpha_compare_op0, alpha_compare_op1); + operands[1] = gen_rtx_EQ (DImode, alpha_compare_op0, alpha_compare_op1); }") (define_expand "sne" @@ -2120,7 +3090,7 @@ if (alpha_compare_fp_p) FAIL; - operands[1] = gen_rtx (EQ, DImode, alpha_compare_op0, alpha_compare_op1); + operands[1] = gen_rtx_EQ (DImode, alpha_compare_op0, alpha_compare_op1); }") (define_expand "slt" @@ -2132,7 +3102,7 @@ if (alpha_compare_fp_p) FAIL; - operands[1] = gen_rtx (LT, DImode, alpha_compare_op0, alpha_compare_op1); + operands[1] = gen_rtx_LT (DImode, alpha_compare_op0, alpha_compare_op1); }") (define_expand "sle" @@ -2144,7 +3114,7 @@ if (alpha_compare_fp_p) FAIL; - operands[1] = gen_rtx (LE, DImode, alpha_compare_op0, alpha_compare_op1); + operands[1] = gen_rtx_LE (DImode, alpha_compare_op0, alpha_compare_op1); }") (define_expand "sgt" @@ -2156,8 +3126,8 @@ if (alpha_compare_fp_p) FAIL; - operands[1] = gen_rtx (LT, DImode, force_reg (DImode, alpha_compare_op1), - alpha_compare_op0); + operands[1] = gen_rtx_LT (DImode, force_reg (DImode, alpha_compare_op1), + alpha_compare_op0); }") (define_expand "sge" @@ -2169,8 +3139,8 @@ if (alpha_compare_fp_p) FAIL; - operands[1] = gen_rtx (LE, DImode, force_reg (DImode, alpha_compare_op1), - alpha_compare_op0); + operands[1] = gen_rtx_LE (DImode, force_reg (DImode, alpha_compare_op1), + alpha_compare_op0); }") (define_expand "sltu" @@ -2182,7 +3152,7 @@ if (alpha_compare_fp_p) FAIL; - operands[1] = gen_rtx (LTU, DImode, alpha_compare_op0, alpha_compare_op1); + operands[1] = gen_rtx_LTU (DImode, alpha_compare_op0, alpha_compare_op1); }") (define_expand "sleu" @@ -2194,7 +3164,7 @@ if (alpha_compare_fp_p) FAIL; - operands[1] = gen_rtx (LEU, DImode, alpha_compare_op0, alpha_compare_op1); + operands[1] = gen_rtx_LEU (DImode, alpha_compare_op0, alpha_compare_op1); }") (define_expand "sgtu" @@ -2206,8 +3176,8 @@ if (alpha_compare_fp_p) FAIL; - operands[1] = gen_rtx (LTU, DImode, force_reg (DImode, alpha_compare_op1), - alpha_compare_op0); + operands[1] = gen_rtx_LTU (DImode, force_reg (DImode, alpha_compare_op1), + alpha_compare_op0); }") (define_expand "sgeu" @@ -2219,184 +3189,58 @@ if (alpha_compare_fp_p) FAIL; - operands[1] = gen_rtx (LEU, DImode, force_reg (DImode, alpha_compare_op1), - alpha_compare_op0); + operands[1] = gen_rtx_LEU (DImode, force_reg (DImode, alpha_compare_op1), + alpha_compare_op0); }") ;; These are the main define_expand's used to make conditional moves. (define_expand "movsicc" - [(set (match_dup 4) (match_operand 1 "comparison_operator" "")) - (set (match_operand:SI 0 "register_operand" "") - (if_then_else:DI (match_dup 5) + [(set (match_operand:SI 0 "register_operand" "") + (if_then_else:DI (match_operand 1 "comparison_operator" "") (match_operand:SI 2 "reg_or_8bit_operand" "") (match_operand:SI 3 "reg_or_8bit_operand" "")))] "" " { - rtx op0,op1; - enum rtx_code code = GET_CODE (operands[1]), code2 = NE; - - if (alpha_compare_fp_p) + if ((operands[1] = alpha_emit_conditional_move (operands[1], SImode)) == 0) FAIL; - switch (code) - { - case EQ: case LE: case LT: - op0 = alpha_compare_op0; - op1 = alpha_compare_op1; - break; - case NE: - code = code2 = EQ; - op0 = alpha_compare_op0; - op1 = alpha_compare_op1; - break; - case GE: - code = LE; - op0 = force_reg (DImode, alpha_compare_op1); - op1 = alpha_compare_op0; - break; - case GT: - code = LT; - op0 = force_reg (DImode, alpha_compare_op1); - op1 = alpha_compare_op0; - break; - default: - FAIL; - } - operands[1] = gen_rtx (code, DImode, op0, op1); - operands[4] = gen_reg_rtx (DImode); - operands[5] = gen_rtx (code2, VOIDmode, operands[4], CONST0_RTX (DImode)); }") (define_expand "movdicc" - [(set (match_dup 4) (match_operand 1 "comparison_operator" "")) - (set (match_operand:DI 0 "register_operand" "") - (if_then_else:DI (match_dup 5) + [(set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (match_operand 1 "comparison_operator" "") (match_operand:DI 2 "reg_or_8bit_operand" "") (match_operand:DI 3 "reg_or_8bit_operand" "")))] "" " { - rtx op0,op1; - enum rtx_code code = GET_CODE (operands[1]), code2 = NE; - - if (alpha_compare_fp_p) + if ((operands[1] = alpha_emit_conditional_move (operands[1], DImode)) == 0) FAIL; - switch (code) - { - case EQ: case LE: case LT: - op0 = alpha_compare_op0; - op1 = alpha_compare_op1; - break; - case NE: - code = code2 = EQ; - op0 = alpha_compare_op0; - op1 = alpha_compare_op1; - break; - case GE: - code = LE; - op0 = force_reg (DImode, alpha_compare_op1); - op1 = alpha_compare_op0; - break; - case GT: - code = LT; - op0 = force_reg (DImode, alpha_compare_op1); - op1 = alpha_compare_op0; - break; - default: - FAIL; - } - operands[1] = gen_rtx (code, DImode, op0, op1); - operands[4] = gen_reg_rtx (DImode); - operands[5] = gen_rtx (code2, VOIDmode, operands[4], CONST0_RTX (DImode)); }") (define_expand "movsfcc" - [(set (match_dup 4) (match_operand 1 "comparison_operator" "")) - (set (match_operand:SF 0 "register_operand" "") - (if_then_else:SF (match_dup 5) - (match_operand:SF 2 "reg_or_fp0_operand" "") - (match_operand:SF 3 "reg_or_fp0_operand" "")))] + [(set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (match_operand 1 "comparison_operator" "") + (match_operand:SF 2 "reg_or_8bit_operand" "") + (match_operand:SF 3 "reg_or_8bit_operand" "")))] "" " { - rtx op0,op1; - enum rtx_code code = GET_CODE (operands[1]), code2 = NE; - - if (!alpha_compare_fp_p) + if ((operands[1] = alpha_emit_conditional_move (operands[1], SFmode)) == 0) FAIL; - switch (code) - { - case EQ: case LE: case LT: - op0 = alpha_compare_op0; - op1 = alpha_compare_op1; - break; - case NE: - /* There isn't a cmptne insn. */ - code = code2 = EQ; - op0 = alpha_compare_op0; - op1 = alpha_compare_op1; - break; - case GE: - code = LE; - op0 = force_reg (DFmode, alpha_compare_op1); - op1 = alpha_compare_op0; - break; - case GT: - code = LT; - op0 = force_reg (DFmode, alpha_compare_op1); - op1 = alpha_compare_op0; - break; - default: - FAIL; - } - operands[1] = gen_rtx (code, DFmode, op0, op1); - operands[4] = gen_reg_rtx (DFmode); - operands[5] = gen_rtx (code2, VOIDmode, operands[4], CONST0_RTX (DFmode)); }") (define_expand "movdfcc" - [(set (match_dup 4) (match_operand 1 "comparison_operator" "")) - (set (match_operand:DF 0 "register_operand" "") - (if_then_else:DF (match_dup 5) - (match_operand:DF 2 "reg_or_fp0_operand" "") - (match_operand:DF 3 "reg_or_fp0_operand" "")))] + [(set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (match_operand 1 "comparison_operator" "") + (match_operand:DF 2 "reg_or_8bit_operand" "") + (match_operand:DF 3 "reg_or_8bit_operand" "")))] "" " { - rtx op0,op1; - enum rtx_code code = GET_CODE (operands[1]), code2 = NE; - - if (!alpha_compare_fp_p) + if ((operands[1] = alpha_emit_conditional_move (operands[1], DFmode)) == 0) FAIL; - switch (code) - { - case EQ: case LE: case LT: - op0 = alpha_compare_op0; - op1 = alpha_compare_op1; - break; - case NE: - /* There isn't a cmptne insn. */ - code = code2 = EQ; - op0 = alpha_compare_op0; - op1 = alpha_compare_op1; - break; - case GE: - code = LE; - op0 = force_reg (DFmode, alpha_compare_op1); - op1 = alpha_compare_op0; - break; - case GT: - code = LT; - op0 = force_reg (DFmode, alpha_compare_op1); - op1 = alpha_compare_op0; - break; - default: - FAIL; - } - operands[1] = gen_rtx (code, DFmode, op0, op1); - operands[4] = gen_reg_rtx (DFmode); - operands[5] = gen_rtx (code2, VOIDmode, operands[4], CONST0_RTX (DFmode)); }") ;; These define_split definitions are used in cases when comparisons have @@ -2451,25 +3295,25 @@ && extended_count (operands[3], DImode, unsignedp) >= 1)) { if (GET_CODE (operands[3]) == CONST_INT) - operands[7] = gen_rtx (PLUS, DImode, operands[2], - GEN_INT (- INTVAL (operands[3]))); + operands[7] = gen_rtx_PLUS (DImode, operands[2], + GEN_INT (- INTVAL (operands[3]))); else - operands[7] = gen_rtx (MINUS, DImode, operands[2], operands[3]); + operands[7] = gen_rtx_MINUS (DImode, operands[2], operands[3]); - operands[8] = gen_rtx (code, VOIDmode, operands[6], const0_rtx); + operands[8] = gen_rtx_fmt_ee (code, VOIDmode, operands[6], const0_rtx); } else if (code == EQ || code == LE || code == LT || code == LEU || code == LTU) { - operands[7] = gen_rtx (code, DImode, operands[2], operands[3]); - operands[8] = gen_rtx (NE, VOIDmode, operands[6], const0_rtx); + operands[7] = gen_rtx_fmt_ee (code, DImode, operands[2], operands[3]); + operands[8] = gen_rtx_NE (VOIDmode, operands[6], const0_rtx); } else { - operands[7] = gen_rtx (reverse_condition (code), DImode, operands[2], - operands[3]); - operands[8] = gen_rtx (EQ, VOIDmode, operands[6], const0_rtx); + operands[7] = gen_rtx_fmt_ee (reverse_condition (code), DImode, + operands[2], operands[3]); + operands[8] = gen_rtx_EQ (VOIDmode, operands[6], const0_rtx); } }") @@ -2498,14 +3342,14 @@ FAIL; if (GET_CODE (operands[3]) == CONST_INT) - tem = gen_rtx (PLUS, SImode, operands[2], - GEN_INT (- INTVAL (operands[3]))); + tem = gen_rtx_PLUS (SImode, operands[2], + GEN_INT (- INTVAL (operands[3]))); else - tem = gen_rtx (MINUS, SImode, operands[2], operands[3]); + tem = gen_rtx_MINUS (SImode, operands[2], operands[3]); - operands[7] = gen_rtx (SIGN_EXTEND, DImode, tem); - operands[8] = gen_rtx (GET_CODE (operands[1]), VOIDmode, operands[6], - const0_rtx); + operands[7] = gen_rtx_SIGN_EXTEND (DImode, tem); + operands[8] = gen_rtx_fmt_ee (GET_CODE (operands[1]), VOIDmode, + operands[6], const0_rtx); }") (define_split @@ -2529,25 +3373,25 @@ && extended_count (operands[3], DImode, unsignedp) >= 1)) { if (GET_CODE (operands[3]) == CONST_INT) - operands[5] = gen_rtx (PLUS, DImode, operands[2], - GEN_INT (- INTVAL (operands[3]))); + operands[5] = gen_rtx_PLUS (DImode, operands[2], + GEN_INT (- INTVAL (operands[3]))); else - operands[5] = gen_rtx (MINUS, DImode, operands[2], operands[3]); + operands[5] = gen_rtx_MINUS (DImode, operands[2], operands[3]); - operands[6] = gen_rtx (code, VOIDmode, operands[4], const0_rtx); + operands[6] = gen_rtx_fmt_ee (code, VOIDmode, operands[4], const0_rtx); } else if (code == EQ || code == LE || code == LT || code == LEU || code == LTU) { - operands[5] = gen_rtx (code, DImode, operands[2], operands[3]); - operands[6] = gen_rtx (NE, VOIDmode, operands[4], const0_rtx); + operands[5] = gen_rtx_fmt_ee (code, DImode, operands[2], operands[3]); + operands[6] = gen_rtx_NE (VOIDmode, operands[4], const0_rtx); } else { - operands[5] = gen_rtx (reverse_condition (code), DImode, operands[2], - operands[3]); - operands[6] = gen_rtx (EQ, VOIDmode, operands[4], const0_rtx); + operands[5] = gen_rtx_fmt_ee (reverse_condition (code), DImode, + operands[2], operands[3]); + operands[6] = gen_rtx_EQ (VOIDmode, operands[4], const0_rtx); } }") @@ -2568,14 +3412,14 @@ { rtx tem; if (GET_CODE (operands[3]) == CONST_INT) - tem = gen_rtx (PLUS, SImode, operands[2], - GEN_INT (- INTVAL (operands[3]))); + tem = gen_rtx_PLUS (SImode, operands[2], + GEN_INT (- INTVAL (operands[3]))); else - tem = gen_rtx (MINUS, SImode, operands[2], operands[3]); + tem = gen_rtx_MINUS (SImode, operands[2], operands[3]); - operands[5] = gen_rtx (SIGN_EXTEND, DImode, tem); - operands[6] = gen_rtx (GET_CODE (operands[1]), VOIDmode, - operands[4], const0_rtx); + operands[5] = gen_rtx_SIGN_EXTEND (DImode, tem); + operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[1]), VOIDmode, + operands[4], const0_rtx); }") ;; We can convert such things as "a > 0xffff" to "t = a & ~ 0xffff; t != 0". @@ -2597,10 +3441,10 @@ " { operands[5] = GEN_INT (~ INTVAL (operands[3])); - operands[6] = gen_rtx (((GET_CODE (operands[1]) == GTU - || GET_CODE (operands[1]) == GT) - ? NE : EQ), - DImode, operands[4], const0_rtx); + operands[6] = gen_rtx_fmt_ee (((GET_CODE (operands[1]) == GTU + || GET_CODE (operands[1]) == GT) + ? NE : EQ), + DImode, operands[4], const0_rtx); }") ;; Here are the CALL and unconditional branch insns. Calls on NT and OSF @@ -2608,11 +3452,15 @@ (define_expand "call" [(use (match_operand:DI 0 "" "")) - (use (match_operand 1 "" ""))] + (use (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" ""))] "" " -{ if (WINDOWS_NT) +{ if (TARGET_WINDOWS_NT) emit_call_insn (gen_call_nt (operands[0], operands[1])); + else if (TARGET_OPEN_VMS) + emit_call_insn (gen_call_vms (operands[0], operands[2])); else emit_call_insn (gen_call_osf (operands[0], operands[1])); @@ -2634,39 +3482,95 @@ if (GET_CODE (operands[0]) != SYMBOL_REF && ! (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 27)) { - rtx tem = gen_rtx (REG, DImode, 27); + rtx tem = gen_rtx_REG (DImode, 27); emit_move_insn (tem, operands[0]); operands[0] = tem; } }") (define_expand "call_nt" - [(parallel [(call (mem:DI (match_operand:DI 0 "" "")) + [(parallel [(call (mem:DI (match_operand 0 "" "")) (match_operand 1 "" "")) (clobber (reg:DI 26))])] "" " { if (GET_CODE (operands[0]) != MEM) abort (); + operands[0] = XEXP (operands[0], 0); + if (GET_CODE (operands[0]) != SYMBOL_REF && GET_CODE (operands[0]) != REG) + operands[0] = force_reg (DImode, operands[0]); +}") - if (GET_CODE (operands[1]) != SYMBOL_REF - && ! (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 27)) +;; +;; call openvms/alpha +;; op 0: symbol ref for called function +;; op 1: next_arg_reg (argument information value for R25) +;; +(define_expand "call_vms" + [(parallel [(call (mem:DI (match_operand 0 "" "")) + (match_operand 1 "" "")) + (use (match_dup 2)) + (use (reg:DI 25)) + (use (reg:DI 26)) + (clobber (reg:DI 27))])] + "" + " +{ if (GET_CODE (operands[0]) != MEM) + abort (); + + operands[0] = XEXP (operands[0], 0); + + /* Always load AI with argument information, then handle symbolic and + indirect call differently. Load RA and set operands[2] to PV in + both cases. */ + + emit_move_insn (gen_rtx_REG (DImode, 25), operands[1]); + if (GET_CODE (operands[0]) == SYMBOL_REF) { - rtx tem = gen_rtx (REG, DImode, 27); - emit_move_insn (tem, operands[1]); - operands[1] = tem; + extern char *savealloc (); + char *linksym, *symbol = XSTR (operands[0], 0); + rtx linkage; + + if (*symbol == '*') + symbol++; + linksym = savealloc (strlen (symbol) + 6); + + alpha_need_linkage (symbol, 0); + + linksym[0] = '$'; + strcpy (linksym+1, symbol); + strcat (linksym, \"..lk\"); + linkage = gen_rtx_SYMBOL_REF (Pmode, linksym); + + emit_move_insn (gen_rtx_REG (Pmode, 26), gen_rtx_MEM (Pmode, linkage)); + + operands[2] + = validize_mem (gen_rtx_MEM (Pmode, plus_constant (linkage, 8))); } + else + { + emit_move_insn (gen_rtx_REG (Pmode, 26), + gen_rtx_MEM (Pmode, plus_constant (operands[0], 8))); + + operands[2] = operands[0]; + } + }") (define_expand "call_value" [(use (match_operand 0 "" "")) (use (match_operand:DI 1 "" "")) - (use (match_operand 2 "" ""))] + (use (match_operand 2 "" "")) + (use (match_operand 3 "" "")) + (use (match_operand 4 "" ""))] "" " -{ if (WINDOWS_NT) +{ if (TARGET_WINDOWS_NT) emit_call_insn (gen_call_value_nt (operands[0], operands[1], operands[2])); + else if (TARGET_OPEN_VMS) + emit_call_insn (gen_call_value_vms (operands[0], operands[1], + operands[3])); else emit_call_insn (gen_call_value_osf (operands[0], operands[1], operands[2])); @@ -2689,7 +3593,7 @@ if (GET_CODE (operands[1]) != SYMBOL_REF && ! (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 27)) { - rtx tem = gen_rtx (REG, DImode, 27); + rtx tem = gen_rtx_REG (DImode, 27); emit_move_insn (tem, operands[1]); operands[1] = tem; } @@ -2697,7 +3601,7 @@ (define_expand "call_value_nt" [(parallel [(set (match_operand 0 "" "") - (call (mem:DI (match_operand:DI 1 "" "")) + (call (mem:DI (match_operand 1 "" "")) (match_operand 2 "" ""))) (clobber (reg:DI 26))])] "" @@ -2706,12 +3610,57 @@ abort (); operands[1] = XEXP (operands[1], 0); - if (GET_CODE (operands[1]) != SYMBOL_REF - && ! (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 27)) + if (GET_CODE (operands[0]) != SYMBOL_REF && GET_CODE (operands[0]) != REG) + operands[1] = force_reg (DImode, operands[1]); +}") + +(define_expand "call_value_vms" + [(parallel [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "" "")) + (match_operand 2 "" ""))) + (use (match_dup 3)) + (use (reg:DI 25)) + (use (reg:DI 26)) + (clobber (reg:DI 27))])] + "" + " +{ if (GET_CODE (operands[1]) != MEM) + abort (); + + operands[1] = XEXP (operands[1], 0); + + /* Always load AI with argument information, then handle symbolic and + indirect call differently. Load RA and set operands[3] to PV in + both cases. */ + + emit_move_insn (gen_rtx_REG (DImode, 25), operands[2]); + if (GET_CODE (operands[1]) == SYMBOL_REF) { - rtx tem = gen_rtx (REG, DImode, 27); - emit_move_insn (tem, operands[1]); - operands[1] = tem; + extern char *savealloc (); + char *linksym, *symbol = XSTR (operands[1], 0); + rtx linkage; + + if (*symbol == '*') + symbol++; + linksym = savealloc (strlen (symbol) + 6); + + alpha_need_linkage (symbol, 0); + linksym[0] = '$'; + strcpy (linksym+1, symbol); + strcat (linksym, \"..lk\"); + linkage = gen_rtx_SYMBOL_REF (Pmode, linksym); + + emit_move_insn (gen_rtx_REG (Pmode, 26), gen_rtx_MEM (Pmode, linkage)); + + operands[3] + = validize_mem (gen_rtx_MEM (Pmode, plus_constant (linkage, 8))); + } + else + { + emit_move_insn (gen_rtx_REG (Pmode, 26), + gen_rtx_MEM (Pmode, plus_constant (operands[1], 8))); + + operands[3] = operands[1]; } }") @@ -2720,46 +3669,81 @@ (match_operand 1 "" "")) (clobber (reg:DI 27)) (clobber (reg:DI 26))] - "! WINDOWS_NT" + "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS" "@ jsr $26,($27),0\;ldgp $29,0($26) - bsr $26,%0..ng + bsr $26,$%0..ng jsr $26,%0\;ldgp $29,0($26)" - [(set_attr "type" "jsr,jsr,ibr")]) + [(set_attr "type" "jsr") + (set_attr "length" "12,*,12")]) (define_insn "" - [(call (mem:DI (match_operand:DI 0 "call_operand" "r,i")) + [(call (mem:DI (match_operand:DI 0 "call_operand" "r,R,i")) (match_operand 1 "" "")) (clobber (reg:DI 26))] - "WINDOWS_NT" + "TARGET_WINDOWS_NT" "@ jsr $26,(%0) - bsr $26,%0" - [(set_attr "type" "jsr")]) + bsr $26,%0 + jsr $26,%0" + [(set_attr "type" "jsr") + (set_attr "length" "*,*,12")]) (define_insn "" + [(call (mem:DI (match_operand:DI 0 "call_operand" "r,i")) + (match_operand 1 "" "")) + (use (match_operand:DI 2 "general_operand" "r,m")) + (use (reg:DI 25)) + (use (reg:DI 26)) + (clobber (reg:DI 27))] + "TARGET_OPEN_VMS" + "@ + bis %2,%2,$27\;jsr $26,0\;ldq $27,0($29) + ldq $27,%2\;jsr $26,%0\;ldq $27,0($29)" + [(set_attr "type" "jsr") + (set_attr "length" "12,16")]) + +(define_insn "" [(set (match_operand 0 "register_operand" "=rf,rf,rf") (call (mem:DI (match_operand:DI 1 "call_operand" "r,R,i")) (match_operand 2 "" ""))) (clobber (reg:DI 27)) (clobber (reg:DI 26))] - "! WINDOWS_NT" + "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS" "@ jsr $26,($27),0\;ldgp $29,0($26) - bsr $26,%1..ng + bsr $26,$%1..ng jsr $26,%1\;ldgp $29,0($26)" - [(set_attr "type" "jsr,jsr,ibr")]) + [(set_attr "type" "jsr") + (set_attr "length" "12,*,12")]) (define_insn "" - [(set (match_operand 0 "register_operand" "=rf,rf") - (call (mem:DI (match_operand:DI 1 "call_operand" "r,i")) + [(set (match_operand 0 "register_operand" "=rf,rf,rf") + (call (mem:DI (match_operand:DI 1 "call_operand" "r,R,i")) (match_operand 2 "" ""))) (clobber (reg:DI 26))] - "WINDOWS_NT" + "TARGET_WINDOWS_NT" "@ jsr $26,(%1) - bsr $26,%1" - [(set_attr "type" "jsr")]) + bsr $26,%1 + jsr $26,%1" + [(set_attr "type" "jsr") + (set_attr "length" "*,*,12")]) + +(define_insn "" + [(set (match_operand 0 "register_operand" "") + (call (mem:DI (match_operand:DI 1 "call_operand" "r,i")) + (match_operand 2 "" ""))) + (use (match_operand:DI 3 "general_operand" "r,m")) + (use (reg:DI 25)) + (use (reg:DI 26)) + (clobber (reg:DI 27))] + "TARGET_OPEN_VMS" + "@ + bis %3,%3,$27\;jsr $26,0\;ldq $27,0($29) + ldq $27,%3\;jsr $26,%1\;ldq $27,0($29)" + [(set_attr "type" "jsr") + (set_attr "length" "12,16")]) ;; Call subroutine returning any type. @@ -2796,7 +3780,8 @@ (define_insn "blockage" [(unspec_volatile [(const_int 0)] 1)] "" - "") + "" + [(set_attr "length" "0")]) (define_insn "jump" [(set (pc) @@ -2811,6 +3796,15 @@ "ret $31,($26),1" [(set_attr "type" "ibr")]) +;; Use a different pattern for functions which have non-trivial +;; epilogues so as not to confuse jump and reorg. +(define_insn "return_internal" + [(use (reg:DI 26)) + (return)] + "" + "ret $31,($26),1" + [(set_attr "type" "ibr")]) + (define_insn "indirect_jump" [(set (pc) (match_operand:DI 0 "register_operand" "r"))] "" @@ -2820,8 +3814,8 @@ (define_insn "nop" [(const_int 0)] "" - "bis $31,$31,$31" - [(set_attr "type" "iaddlog")]) + "nop" + [(set_attr "type" "ilog")]) (define_expand "tablejump" [(use (match_operand:SI 0 "register_operand" "")) @@ -2829,8 +3823,10 @@ "" " { - if (WINDOWS_NT) + if (TARGET_WINDOWS_NT) emit_jump_insn (gen_tablejump_nt (operands[0], operands[1])); + else if (TARGET_OPEN_VMS) + emit_jump_insn (gen_tablejump_vms (operands[0], operands[1])); else emit_jump_insn (gen_tablejump_osf (operands[0], operands[1])); @@ -2858,12 +3854,27 @@ " { operands[3] = gen_reg_rtx (DImode); }") +;; +;; tablejump, openVMS way +;; op 0: offset +;; op 1: label preceding jump-table +;; +(define_expand "tablejump_vms" + [(set (match_dup 2) + (match_operand:DI 0 "register_operand" "")) + (set (pc) + (plus:DI (match_dup 2) + (label_ref:DI (match_operand 1 "" ""))))] + "" + " +{ operands[2] = gen_reg_rtx (DImode); }") + (define_insn "" [(set (pc) (plus:DI (match_operand:DI 0 "register_operand" "r") (label_ref:DI (match_operand 1 "" "")))) (clobber (match_scratch:DI 2 "=r"))] - "! WINDOWS_NT && next_active_insn (insn) != 0 + "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS && next_active_insn (insn) != 0 && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC && PREV_INSN (next_active_insn (insn)) == operands[1]" "* @@ -2900,13 +3911,14 @@ else return \"addq %0,$29,%2\;jmp $31,(%2),0\"; }" - [(set_attr "type" "ibr")]) + [(set_attr "type" "ibr") + (set_attr "length" "8")]) (define_insn "" [(set (pc) (match_operand:DI 0 "register_operand" "r")) (use (label_ref (match_operand 1 "" "")))] - "WINDOWS_NT && next_active_insn (insn) != 0 + "TARGET_WINDOWS_NT && next_active_insn (insn) != 0 && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC && PREV_INSN (next_active_insn (insn)) == operands[1]" "* @@ -2945,12 +3957,30 @@ }" [(set_attr "type" "ibr")]) +;; +;; op 0 is table offset +;; op 1 is table label +;; + +(define_insn "" + [(set (pc) + (plus:DI (match_operand 0 "register_operand" "r") + (label_ref (match_operand 1 "" ""))))] + "TARGET_OPEN_VMS" + "jmp $31,(%0),0" + [(set_attr "type" "ibr")]) + ;; Cache flush. Used by INITIALIZE_TRAMPOLINE. 0x86 is PAL_imb, but we don't ;; want to have to include pal.h in our .s file. -(define_insn "" +;; +;; Technically the type for call_pal is jsr, but we use that for determining +;; if we need a GP. Use ibr instead since it has the same EV5 scheduling +;; characteristics. +(define_insn "imb" [(unspec_volatile [(const_int 0)] 0)] "" - "call_pal 0x86") + "call_pal 0x86" + [(set_attr "type" "ibr")]) ;; Finally, we have the basic data motion insns. The byte and word insns ;; are done via define_expand. Start with the floating-point insns, since @@ -2959,32 +3989,70 @@ (define_insn "" [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m,f,f,f,m") (match_operand:SF 1 "input_operand" "rG,m,rG,f,G,m,fG"))] - "register_operand (operands[0], SFmode) - || reg_or_fp0_operand (operands[1], SFmode)" + "! TARGET_CIX + && (register_operand (operands[0], SFmode) + || reg_or_fp0_operand (operands[1], SFmode))" + "@ + bis %r1,%r1,%0 + ldl %0,%1 + stl %r1,%0 + cpys %1,%1,%0 + cpys $f31,$f31,%0 + ld%, %0,%1 + st%, %R1,%0" + [(set_attr "type" "ilog,ild,ist,fcpys,fcpys,fld,fst")]) + +(define_insn "" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m,f,f,f,m,f,*r") + (match_operand:SF 1 "input_operand" "rG,m,rG,f,G,m,fG,r,*f"))] + "TARGET_CIX + && (register_operand (operands[0], SFmode) + || reg_or_fp0_operand (operands[1], SFmode))" "@ bis %r1,%r1,%0 ldl %0,%1 stl %r1,%0 cpys %1,%1,%0 cpys $f31,$f31,%0 - lds %0,%1 - sts %R1,%0" - [(set_attr "type" "iaddlog,ld,st,fpop,fpop,ld,st")]) + ld%, %0,%1 + st%, %R1,%0 + itofs %1,%0 + ftois %1,%0" + [(set_attr "type" "ilog,ild,ist,fcpys,fcpys,fld,fst,itof,ftoi")]) (define_insn "" [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,f,f,f,m") (match_operand:DF 1 "input_operand" "rG,m,rG,f,G,m,fG"))] - "register_operand (operands[0], DFmode) - || reg_or_fp0_operand (operands[1], DFmode)" + "! TARGET_CIX + && (register_operand (operands[0], DFmode) + || reg_or_fp0_operand (operands[1], DFmode))" "@ bis %r1,%r1,%0 ldq %0,%1 stq %r1,%0 cpys %1,%1,%0 cpys $f31,$f31,%0 - ldt %0,%1 - stt %R1,%0" - [(set_attr "type" "iaddlog,ld,st,fpop,fpop,ld,st")]) + ld%- %0,%1 + st%- %R1,%0" + [(set_attr "type" "ilog,ild,ist,fcpys,fcpys,fld,fst")]) + +(define_insn "" + [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,f,f,f,m,f,*r") + (match_operand:DF 1 "input_operand" "rG,m,rG,f,G,m,fG,r,*f"))] + "TARGET_CIX + && (register_operand (operands[0], DFmode) + || reg_or_fp0_operand (operands[1], DFmode))" + "@ + bis %r1,%r1,%0 + ldq %0,%1 + stq %r1,%0 + cpys %1,%1,%0 + cpys $f31,$f31,%0 + ld%- %0,%1 + st%- %R1,%0 + itoft %1,%0 + ftoit %1,%0" + [(set_attr "type" "ilog,ild,ist,fcpys,fcpys,fld,fst,itof,ftoi")]) (define_expand "movsf" [(set (match_operand:SF 0 "nonimmediate_operand" "") @@ -3011,8 +4079,9 @@ (define_insn "" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,f,f,f,m") (match_operand:SI 1 "input_operand" "r,J,I,K,L,m,rJ,f,J,m,fG"))] - "! WINDOWS_NT && (register_operand (operands[0], SImode) - || reg_or_0_operand (operands[1], SImode))" + "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS && ! TARGET_CIX + && (register_operand (operands[0], SImode) + || reg_or_0_operand (operands[1], SImode))" "@ bis %1,%1,%0 bis $31,$31,%0 @@ -3023,15 +4092,38 @@ stl %r1,%0 cpys %1,%1,%0 cpys $f31,$f31,%0 - lds %0,%1 - sts %R1,%0" - [(set_attr "type" "iaddlog,iaddlog,iaddlog,iaddlog,iaddlog,ld,st,fpop,fpop,ld,st")]) + ld%, %0,%1 + st%, %R1,%0" + [(set_attr "type" "ilog,ilog,ilog,iadd,iadd,ild,ist,fcpys,fcpys,fld,fst")]) + +(define_insn "" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,f,f,f,m,r,*f") + (match_operand:SI 1 "input_operand" "r,J,I,K,L,m,rJ,f,J,m,fG,f,*r"))] + "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS && TARGET_CIX + && (register_operand (operands[0], SImode) + || reg_or_0_operand (operands[1], SImode))" + "@ + bis %1,%1,%0 + bis $31,$31,%0 + bis $31,%1,%0 + lda %0,%1 + ldah %0,%h1 + ldl %0,%1 + stl %r1,%0 + cpys %1,%1,%0 + cpys $f31,$f31,%0 + ld%, %0,%1 + st%, %R1,%0 + ftois %1,%0 + itofs %1,%0" + [(set_attr "type" "ilog,ilog,ilog,iadd,iadd,ild,ist,fcpys,fcpys,fld,fst,ftoi,itof")]) (define_insn "" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,r,r,m,f,f,f,m") (match_operand:SI 1 "input_operand" "r,J,I,K,L,s,m,rJ,f,J,m,fG"))] - "WINDOWS_NT && (register_operand (operands[0], SImode) - || reg_or_0_operand (operands[1], SImode))" + "(TARGET_WINDOWS_NT || TARGET_OPEN_VMS) + && (register_operand (operands[0], SImode) + || reg_or_0_operand (operands[1], SImode))" "@ bis %1,%1,%0 bis $31,$31,%0 @@ -3043,15 +4135,16 @@ stl %r1,%0 cpys %1,%1,%0 cpys $f31,$f31,%0 - lds %0,%1 - sts %R1,%0" - [(set_attr "type" "iaddlog,iaddlog,iaddlog,iaddlog,iaddlog,ldsym,ld,st,fpop,fpop,ld,st")]) + ld%, %0,%1 + st%, %R1,%0" + [(set_attr "type" "ilog,ilog,ilog,iadd,iadd,ldsym,ild,ist,fcpys,fcpys,fld,fst")]) (define_insn "" [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,f,f") (match_operand:HI 1 "input_operand" "r,J,I,n,f,J"))] - "register_operand (operands[0], HImode) - || register_operand (operands[1], HImode)" + "! TARGET_BWX + && (register_operand (operands[0], HImode) + || register_operand (operands[1], HImode))" "@ bis %1,%1,%0 bis $31,$31,%0 @@ -3059,21 +4152,56 @@ lda %0,%L1 cpys %1,%1,%0 cpys $f31,$f31,%0" - [(set_attr "type" "iaddlog,iaddlog,iaddlog,iaddlog,fpop,fpop")]) + [(set_attr "type" "ilog,ilog,ilog,iadd,fcpys,fcpys")]) + +(define_insn "" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,r,m,f,f") + (match_operand:HI 1 "input_operand" "r,J,I,n,m,rJ,f,J"))] + "TARGET_BWX + && (register_operand (operands[0], HImode) + || reg_or_0_operand (operands[1], HImode))" + "@ + bis %1,%1,%0 + bis $31,$31,%0 + bis $31,%1,%0 + lda %0,%L1 + ldwu %0,%1 + stw %r1,%0 + cpys %1,%1,%0 + cpys $f31,$f31,%0" + [(set_attr "type" "ilog,ilog,ilog,iadd,ild,ist,fcpys,fcpys")]) (define_insn "" [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,r,f,f") (match_operand:QI 1 "input_operand" "r,J,I,n,f,J"))] - "register_operand (operands[0], QImode) - || register_operand (operands[1], QImode)" + "! TARGET_BWX + && (register_operand (operands[0], QImode) + || register_operand (operands[1], QImode))" + "@ + bis %1,%1,%0 + bis $31,$31,%0 + bis $31,%1,%0 + lda %0,%L1 + cpys %1,%1,%0 + cpys $f31,$f31,%0" + [(set_attr "type" "ilog,ilog,ilog,iadd,fcpys,fcpys")]) + +(define_insn "" + [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,r,r,m,f,f") + (match_operand:QI 1 "input_operand" "r,J,I,n,m,rJ,f,J"))] + "TARGET_BWX + && (register_operand (operands[0], QImode) + || reg_or_0_operand (operands[1], QImode))" "@ bis %1,%1,%0 bis $31,$31,%0 bis $31,%1,%0 lda %0,%L1 + ldbu %0,%1 + stb %r1,%0 cpys %1,%1,%0 cpys $f31,$f31,%0" - [(set_attr "type" "iaddlog,iaddlog,iaddlog,iaddlog,fpop,fpop")]) + [(set_attr "type" "ilog,ilog,ilog,iadd,ild,ist,fcpys,fcpys")]) ;; We do two major things here: handle mem->mem and construct long ;; constants. @@ -3121,8 +4249,9 @@ (define_insn "" [(set (match_operand:DI 0 "general_operand" "=r,r,r,r,r,r,r,m,f,f,f,Q") (match_operand:DI 1 "input_operand" "r,J,I,K,L,s,m,rJ,f,J,Q,fG"))] - "register_operand (operands[0], DImode) - || reg_or_0_operand (operands[1], DImode)" + "! TARGET_CIX + && (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], DImode))" "@ bis %1,%1,%0 bis $31,$31,%0 @@ -3136,7 +4265,30 @@ cpys $f31,$f31,%0 ldt %0,%1 stt %R1,%0" - [(set_attr "type" "iaddlog,iaddlog,iaddlog,iaddlog,iaddlog,ldsym,ld,st,fpop,fpop,ld,st")]) + [(set_attr "type" "ilog,ilog,ilog,iadd,iadd,ldsym,ild,ist,fcpys,fcpys,fld,fst")]) + +(define_insn "" + [(set (match_operand:DI 0 "general_operand" "=r,r,r,r,r,r,r,m,f,f,f,Q,r,*f") + (match_operand:DI 1 "input_operand" "r,J,I,K,L,s,m,rJ,f,J,Q,fG,f,*r"))] + "TARGET_CIX + && (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], DImode))" + "@ + bis %1,%1,%0 + bis $31,$31,%0 + bis $31,%1,%0 + lda %0,%1 + ldah %0,%h1 + lda %0,%1 + ldq%A1 %0,%1 + stq%A0 %r1,%0 + cpys %1,%1,%0 + cpys $f31,$f31,%0 + ldt %0,%1 + stt %R1,%0 + ftoit %1,%0 + itoft %1,%0" + [(set_attr "type" "ilog,ilog,ilog,iadd,iadd,ldsym,ild,ist,fcpys,fcpys,fld,fst,ftoi,itof")]) ;; We do three major things here: handle mem->mem, put 64-bit constants in ;; memory, and construct long 32-bit constants. @@ -3166,15 +4318,39 @@ } else if (CONSTANT_P (operands[1])) { - operands[1] = force_const_mem (DImode, operands[1]); - if (reload_in_progress) + if (TARGET_BUILD_CONSTANTS) { - emit_move_insn (operands[0], XEXP (operands[1], 0)); - operands[1] = copy_rtx (operands[1]); - XEXP (operands[1], 0) = operands[0]; +#if HOST_BITS_PER_WIDE_INT == 64 + HOST_WIDE_INT i; + + if (GET_CODE (operands[1]) == CONST_INT) + i = INTVAL (operands[1]); + else if (GET_CODE (operands[1]) == CONST_DOUBLE) + i = CONST_DOUBLE_LOW (operands[1]); + else + abort(); + + tem = alpha_emit_set_long_const (operands[0], i); + if (rtx_equal_p (tem, operands[0])) + DONE; + else + operands[1] = tem; +#else + abort(); +#endif } else - operands[1] = validize_mem (operands[1]); + { + operands[1] = force_const_mem (DImode, operands[1]); + if (reload_in_progress) + { + emit_move_insn (operands[0], XEXP (operands[1], 0)); + operands[1] = copy_rtx (operands[1]); + XEXP (operands[1], 0) = operands[0]; + } + else + operands[1] = validize_mem (operands[1]); + } } else abort (); @@ -3230,16 +4406,10 @@ "" "") -;; Similar for unaligned loads. For QImode, we use the sequence from the -;; Alpha Architecture manual. However, for HImode, we do not. HImode pointers -;; are normally aligned to the byte boundary, so an HImode object cannot -;; cross a longword boundary. We could use a sequence similar to that for -;; QImode, but that would fail if the pointer, was, in fact, not aligned. -;; Instead, we clear bit 1 in the address and do an ldl. If the low-order -;; bit was not aligned, this will trap and the trap handler will do what is -;; needed. +;; Similar for unaligned loads, where we use the sequence from the +;; Alpha Architecture manual. ;; -;; Here operand 1 is the address. Operands 2 and 3 are temporaries, where +;; Operand 1 is the address. Operands 2 and 3 are temporaries, where ;; operand 3 can overlap the input and output registers. (define_expand "unaligned_loadqi" @@ -3255,26 +4425,19 @@ "" "") -;; For this, the address must already be in a register. We also need two -;; DImode temporaries, neither of which may overlap the input (and hence the -;; output, since they might be the same register), but both of which may -;; be the same. - (define_expand "unaligned_loadhi" [(set (match_operand:DI 2 "register_operand" "") - (and:DI (match_operand:DI 1 "register_operand" "") - (const_int -7))) + (mem:DI (and:DI (match_operand:DI 1 "address_operand" "") + (const_int -8)))) (set (match_operand:DI 3 "register_operand" "") - (mem:DI (match_dup 2))) - (set (match_operand:DI 4 "register_operand" "") - (and:DI (match_dup 1) (const_int -2))) - (set (subreg:DI (match_operand:HI 0 "register_operand" "") 0) - (zero_extract:DI (match_dup 3) + (match_dup 1)) + (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0) + (zero_extract:DI (match_dup 2) (const_int 16) - (ashift:DI (match_dup 4) (const_int 3))))] + (ashift:DI (match_dup 3) (const_int 3))))] "" "") - + ;; Storing an aligned byte or word requires two temporaries. Operand 0 is the ;; aligned SImode MEM. Operand 1 is the register containing the ;; byte or word to store. Operand 2 is the number of bits within the word that @@ -3297,8 +4460,8 @@ << INTVAL (operands[2]))); }") -;; For the unaligned byte case, we use code similar to that in the -;; Architecture book, but reordered to lower the number of registers +;; For the unaligned byte and halfword cases, we use code similar to that +;; in the ;; Architecture book, but reordered to lower the number of registers ;; required. Operand 0 is the address. Operand 1 is the data to store. ;; Operands 2, 3, and 4 are DImode temporaries, where operands 2 and 4 may ;; be the same temporary, if desired. If the address is in a register, @@ -3323,42 +4486,22 @@ "" "") -;; This is the code for storing into an unaligned short. It uses the same -;; trick as loading from an unaligned short. It needs lots of temporaries. -;; However, during reload, we only have two registers available. So we -;; repeat code so that only two temporaries are available. During RTL -;; generation, we can use different pseudos for each temporary and CSE -;; will remove the redundancies. During reload, we have to settle with -;; what we get. Luckily, unaligned accesses of this kind produced during -;; reload are quite rare. -;; -;; Operand 0 is the address of the memory location. Operand 1 contains the -;; data to store. The rest of the operands are all temporaries, with -;; various overlap possibilities during reload. See reload_outhi for -;; details of this use. - (define_expand "unaligned_storehi" - [(set (match_operand:DI 2 "register_operand" "") - (match_operand:DI 0 "address_operand" "")) - (set (match_operand:DI 3 "register_operand" "") - (and:DI (match_dup 2) (const_int -7))) - (set (match_operand:DI 4 "register_operand" "") - (mem:DI (match_dup 3))) - (set (match_operand:DI 10 "register_operand" "") - (and:DI (match_dup 2) (const_int -2))) - (set (match_operand:DI 5 "register_operand" "") + [(set (match_operand:DI 3 "register_operand" "") + (mem:DI (and:DI (match_operand:DI 0 "address_operand" "") + (const_int -8)))) + (set (match_operand:DI 2 "register_operand" "") + (match_dup 0)) + (set (match_dup 3) (and:DI (not:DI (ashift:DI (const_int 65535) - (ashift:DI (match_dup 10) (const_int 3)))) - (match_dup 4))) - (set (match_operand:DI 6 "register_operand" "") + (ashift:DI (match_dup 2) (const_int 3)))) + (match_dup 3))) + (set (match_operand:DI 4 "register_operand" "") (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "")) - (ashift:DI (match_dup 10) (const_int 3)))) - (set (match_operand:DI 7 "register_operand" "") - (ior:DI (match_dup 5) (match_dup 6))) - (set (match_operand:DI 8 "register_operand" "") (match_dup 0)) - (set (match_operand:DI 9 "register_operand" "") - (and:DI (match_dup 8) (const_int -7))) - (set (mem:DI (match_dup 9)) (match_dup 7))] + (ashift:DI (match_dup 2) (const_int 3)))) + (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3))) + (set (mem:DI (and:DI (match_dup 0) (const_int -8))) + (match_dup 4))] "" "") @@ -3371,7 +4514,25 @@ (match_operand:QI 1 "general_operand" ""))] "" " -{ extern rtx get_unaligned_address (); +{ + if (TARGET_BWX) + { + if (GET_CODE (operands[0]) == MEM + && ! reg_or_0_operand (operands[1], QImode)) + operands[1] = force_reg (QImode, operands[1]); + + if (GET_CODE (operands[1]) == CONST_INT + && ! input_operand (operands[1], QImode)) + { + operands[1] = alpha_emit_set_const (operands[0], QImode, + INTVAL (operands[1]), 3); + + if (rtx_equal_p (operands[0], operands[1])) + DONE; + } + + goto def; + } /* If the output is not a register, the input must be. */ if (GET_CODE (operands[0]) == MEM) @@ -3394,7 +4555,7 @@ { rtx aligned_mem, bitnum; rtx scratch = (reload_in_progress - ? gen_rtx (REG, SImode, REGNO (operands[0])) + ? gen_rtx_REG (SImode, REGNO (operands[0])) : gen_reg_rtx (SImode)); get_aligned_mem (operands[1], &aligned_mem, &bitnum); @@ -3410,9 +4571,10 @@ rtx temp1 = gen_reg_rtx (DImode); rtx temp2 = gen_reg_rtx (DImode); - rtx seq = gen_unaligned_loadqi (operands[0], - get_unaligned_address (operands[1]), - temp1, temp2); + rtx seq + = gen_unaligned_loadqi (operands[0], + get_unaligned_address (operands[1], 0), + temp1, temp2); alpha_set_memflags (seq, operands[1]); emit_insn (seq); @@ -3446,7 +4608,8 @@ rtx temp1 = gen_reg_rtx (DImode); rtx temp2 = gen_reg_rtx (DImode); rtx temp3 = gen_reg_rtx (DImode); - rtx seq = gen_unaligned_storeqi (get_unaligned_address (operands[0]), + rtx seq + = gen_unaligned_storeqi (get_unaligned_address (operands[0], 0), operands[1], temp1, temp2, temp3); alpha_set_memflags (seq, operands[0]); @@ -3454,6 +4617,7 @@ } DONE; } + def:; }") (define_expand "movhi" @@ -3461,7 +4625,25 @@ (match_operand:HI 1 "general_operand" ""))] "" " -{ extern rtx get_unaligned_address (); +{ + if (TARGET_BWX) + { + if (GET_CODE (operands[0]) == MEM + && ! reg_or_0_operand (operands[1], HImode)) + operands[1] = force_reg (HImode, operands[1]); + + if (GET_CODE (operands[1]) == CONST_INT + && ! input_operand (operands[1], HImode)) + { + operands[1] = alpha_emit_set_const (operands[0], HImode, + INTVAL (operands[1]), 3); + + if (rtx_equal_p (operands[0], operands[1])) + DONE; + } + + goto def; + } /* If the output is not a register, the input must be. */ if (GET_CODE (operands[0]) == MEM) @@ -3484,7 +4666,7 @@ { rtx aligned_mem, bitnum; rtx scratch = (reload_in_progress - ? gen_rtx (REG, SImode, REGNO (operands[0])) + ? gen_rtx_REG (SImode, REGNO (operands[0])) : gen_reg_rtx (SImode)); get_aligned_mem (operands[1], &aligned_mem, &bitnum); @@ -3494,16 +4676,16 @@ } else { - rtx addr - = force_reg (DImode, - force_operand (get_unaligned_address (operands[1]), - NULL_RTX)); - rtx scratch1 = gen_reg_rtx (DImode); - rtx scratch2 = gen_reg_rtx (DImode); - rtx scratch3 = gen_reg_rtx (DImode); + /* Don't pass these as parameters since that makes the generated + code depend on parameter evaluation order which will cause + bootstrap failures. */ - rtx seq = gen_unaligned_loadhi (operands[0], addr, scratch1, - scratch2, scratch3); + rtx temp1 = gen_reg_rtx (DImode); + rtx temp2 = gen_reg_rtx (DImode); + rtx seq + = gen_unaligned_loadhi (operands[0], + get_unaligned_address (operands[1], 0), + temp1, temp2); alpha_set_memflags (seq, operands[1]); emit_insn (seq); @@ -3537,17 +4719,9 @@ rtx temp1 = gen_reg_rtx (DImode); rtx temp2 = gen_reg_rtx (DImode); rtx temp3 = gen_reg_rtx (DImode); - rtx temp4 = gen_reg_rtx (DImode); - rtx temp5 = gen_reg_rtx (DImode); - rtx temp6 = gen_reg_rtx (DImode); - rtx temp7 = gen_reg_rtx (DImode); - rtx temp8 = gen_reg_rtx (DImode); - rtx temp9 = gen_reg_rtx (DImode); - - rtx seq = gen_unaligned_storehi (get_unaligned_address (operands[0]), - operands[1], temp1, temp2,temp3, - temp4, temp5, temp6,temp7, - temp8, temp9); + rtx seq + = gen_unaligned_storehi (get_unaligned_address (operands[0], 0), + operands[1], temp1, temp2, temp3); alpha_set_memflags (seq, operands[0]); emit_insn (seq); @@ -3555,6 +4729,7 @@ DONE; } + def:; }") ;; Here are the versions for reload. Note that in the unaligned cases @@ -3565,18 +4740,20 @@ [(parallel [(match_operand:QI 0 "register_operand" "=r") (match_operand:QI 1 "unaligned_memory_operand" "m") (match_operand:TI 2 "register_operand" "=&r")])] - "" + "! TARGET_BWX" " -{ extern rtx get_unaligned_address (); - rtx addr = get_unaligned_address (operands[1]); +{ + rtx addr = get_unaligned_address (operands[1], 0); + /* It is possible that one of the registers we got for operands[2] might coincide with that of operands[0] (which is why we made it TImode). Pick the other one to use as our scratch. */ - rtx scratch = gen_rtx (REG, DImode, - REGNO (operands[0]) == REGNO (operands[2]) - ? REGNO (operands[2]) + 1 : REGNO (operands[2])); + rtx scratch = gen_rtx_REG (DImode, + REGNO (operands[0]) == REGNO (operands[2]) + ? REGNO (operands[2]) + 1 : REGNO (operands[2])); + rtx seq = gen_unaligned_loadqi (operands[0], addr, scratch, - gen_rtx (REG, DImode, REGNO (operands[0]))); + gen_rtx_REG (DImode, REGNO (operands[0]))); alpha_set_memflags (seq, operands[1]); emit_insn (seq); @@ -3587,21 +4764,21 @@ [(parallel [(match_operand:HI 0 "register_operand" "=r") (match_operand:HI 1 "unaligned_memory_operand" "m") (match_operand:TI 2 "register_operand" "=&r")])] - "" + "! TARGET_BWX" " -{ extern rtx get_unaligned_address (); - rtx addr = get_unaligned_address (operands[1]); - rtx scratch1 = gen_rtx (REG, DImode, REGNO (operands[2])); - rtx scratch2 = gen_rtx (REG, DImode, REGNO (operands[2]) + 1); - rtx seq; +{ + rtx addr = get_unaligned_address (operands[1], 0); + + /* It is possible that one of the registers we got for operands[2] + might coincide with that of operands[0] (which is why we made + it TImode). Pick the other one to use as our scratch. */ + rtx scratch = gen_rtx_REG (DImode, + REGNO (operands[0]) == REGNO (operands[2]) + ? REGNO (operands[2]) + 1 : REGNO (operands[2])); + + rtx seq = gen_unaligned_loadhi (operands[0], addr, scratch, + gen_rtx_REG (DImode, REGNO (operands[0]))); - if (GET_CODE (addr) != REG) - { - emit_insn (gen_rtx (SET, VOIDmode, scratch2, addr)); - addr = scratch2; - } - - seq = gen_unaligned_loadhi (operands[0], addr, scratch1, scratch1, scratch2); alpha_set_memflags (seq, operands[1]); emit_insn (seq); DONE; @@ -3611,10 +4788,9 @@ [(parallel [(match_operand:QI 0 "any_memory_operand" "=m") (match_operand:QI 1 "register_operand" "r") (match_operand:TI 2 "register_operand" "=&r")])] - "" + "! TARGET_BWX" " -{ extern rtx get_unaligned_address (); - +{ if (aligned_memory_operand (operands[0], QImode)) { rtx aligned_mem, bitnum; @@ -3622,15 +4798,15 @@ get_aligned_mem (operands[0], &aligned_mem, &bitnum); emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum, - gen_rtx (REG, SImode, REGNO (operands[2])), - gen_rtx (REG, SImode, - REGNO (operands[2]) + 1))); + gen_rtx_REG (SImode, REGNO (operands[2])), + gen_rtx_REG (SImode, + REGNO (operands[2]) + 1))); } else { - rtx addr = get_unaligned_address (operands[0]); - rtx scratch1 = gen_rtx (REG, DImode, REGNO (operands[2])); - rtx scratch2 = gen_rtx (REG, DImode, REGNO (operands[2]) + 1); + rtx addr = get_unaligned_address (operands[0], 0); + rtx scratch1 = gen_rtx_REG (DImode, REGNO (operands[2])); + rtx scratch2 = gen_rtx_REG (DImode, REGNO (operands[2]) + 1); rtx scratch3 = scratch1; rtx seq; @@ -3650,10 +4826,9 @@ [(parallel [(match_operand:HI 0 "any_memory_operand" "=m") (match_operand:HI 1 "register_operand" "r") (match_operand:TI 2 "register_operand" "=&r")])] - "" + "! TARGET_BWX" " -{ extern rtx get_unaligned_address (); - +{ if (aligned_memory_operand (operands[0], HImode)) { rtx aligned_mem, bitnum; @@ -3661,22 +4836,23 @@ get_aligned_mem (operands[0], &aligned_mem, &bitnum); emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum, - gen_rtx (REG, SImode, REGNO (operands[2])), - gen_rtx (REG, SImode, - REGNO (operands[2]) + 1))); + gen_rtx_REG (SImode, REGNO (operands[2])), + gen_rtx_REG (SImode, + REGNO (operands[2]) + 1))); } else { - rtx addr = get_unaligned_address (operands[0]); - rtx scratch1 = gen_rtx (REG, DImode, REGNO (operands[2])); - rtx scratch2 = gen_rtx (REG, DImode, REGNO (operands[2]) + 1); - rtx scratch_a = GET_CODE (addr) == REG ? addr : scratch1; + rtx addr = get_unaligned_address (operands[0], 0); + rtx scratch1 = gen_rtx_REG (DImode, REGNO (operands[2])); + rtx scratch2 = gen_rtx_REG (DImode, REGNO (operands[2]) + 1); + rtx scratch3 = scratch1; rtx seq; - seq = gen_unaligned_storehi (addr, operands[1], scratch_a, - scratch2, scratch2, scratch2, - scratch1, scratch2, scratch_a, - scratch1, scratch_a); + if (GET_CODE (addr) == REG) + scratch1 = addr; + + seq = gen_unaligned_storehi (addr, operands[1], scratch1, + scratch2, scratch3); alpha_set_memflags (seq, operands[0]); emit_insn (seq); } @@ -3684,14 +4860,133 @@ DONE; }") +;; Bit field extract patterns which use ext[wlq][lh] + +(define_expand "extv" + [(set (match_operand:DI 0 "register_operand" "") + (sign_extract:DI (match_operand:QI 1 "memory_operand" "") + (match_operand:DI 2 "immediate_operand" "") + (match_operand:DI 3 "immediate_operand" "")))] + "" + " +{ + /* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries. */ + if (INTVAL (operands[3]) % 8 != 0 + || (INTVAL (operands[2]) != 16 + && INTVAL (operands[2]) != 32 + && INTVAL (operands[2]) != 64)) + FAIL; + + /* From mips.md: extract_bit_field doesn't verify that our source + matches the predicate, so we force it to be a MEM here. */ + if (GET_CODE (operands[1]) != MEM) + FAIL; + + alpha_expand_unaligned_load (operands[0], operands[1], + INTVAL (operands[2]) / 8, + INTVAL (operands[3]) / 8, 1); + DONE; +}") + +(define_expand "extzv" + [(set (match_operand:DI 0 "register_operand" "") + (zero_extract:DI (match_operand:DI 1 "general_operand" "") + (match_operand:DI 2 "immediate_operand" "") + (match_operand:DI 3 "immediate_operand" "")))] + "" + " +{ + /* We can do 8, 16, 32 and 64 bit fields, if aligned on byte boundaries. */ + if (INTVAL (operands[3]) % 8 != 0 + || (INTVAL (operands[2]) != 8 + && INTVAL (operands[2]) != 16 + && INTVAL (operands[2]) != 32 + && INTVAL (operands[2]) != 64)) + FAIL; + + if (GET_CODE (operands[1]) == MEM) + { + /* Fail 8 bit fields, falling back on a simple byte load. */ + if (INTVAL (operands[2]) == 8) + FAIL; + + alpha_expand_unaligned_load (operands[0], operands[1], + INTVAL (operands[2]) / 8, + INTVAL (operands[3]) / 8, 0); + DONE; + } +}") + +(define_expand "insv" + [(set (zero_extract:DI (match_operand:QI 0 "memory_operand" "") + (match_operand:DI 1 "immediate_operand" "") + (match_operand:DI 2 "immediate_operand" "")) + (match_operand:DI 3 "register_operand" ""))] + "" + " +{ + /* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries. */ + if (INTVAL (operands[2]) % 8 != 0 + || (INTVAL (operands[1]) != 16 + && INTVAL (operands[1]) != 32 + && INTVAL (operands[1]) != 64)) + FAIL; + + /* From mips.md: store_bit_field doesn't verify that our source + matches the predicate, so we force it to be a MEM here. */ + if (GET_CODE (operands[0]) != MEM) + FAIL; + + alpha_expand_unaligned_store (operands[0], operands[3], + INTVAL (operands[1]) / 8, + INTVAL (operands[2]) / 8); + DONE; +}") + + + +;; Block move/clear, see alpha.c for more details. +;; Argument 0 is the destination +;; Argument 1 is the source +;; Argument 2 is the length +;; Argument 3 is the alignment + +(define_expand "movstrqi" + [(parallel [(set (match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "")) + (use (match_operand:DI 2 "immediate_operand" "")) + (use (match_operand:DI 3 "immediate_operand" ""))])] + "" + " +{ + if (alpha_expand_block_move (operands)) + DONE; + else + FAIL; +}") + +(define_expand "clrstrqi" + [(parallel [(set (match_operand:BLK 0 "general_operand" "") + (const_int 0)) + (use (match_operand:DI 1 "immediate_operand" "")) + (use (match_operand:DI 2 "immediate_operand" ""))])] + "" + " +{ + if (alpha_expand_block_clear (operands)) + DONE; + else + FAIL; +}") + ;; Subroutine of stack space allocation. Perform a stack probe. (define_expand "probe_stack" [(set (match_dup 1) (match_operand:DI 0 "const_int_operand" ""))] "" " { - operands[1] = gen_rtx (MEM, DImode, plus_constant (stack_pointer_rtx, - INTVAL (operands[0]))); + operands[1] = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, + INTVAL (operands[0]))); MEM_VOLATILE_P (operands[1]) = 1; operands[0] = const0_rtx; @@ -3706,14 +5001,16 @@ (define_expand "allocate_stack" [(set (reg:DI 30) (plus:DI (reg:DI 30) - (match_operand:DI 0 "reg_or_cint_operand" "")))] + (match_operand:DI 1 "reg_or_cint_operand" ""))) + (set (match_operand:DI 0 "register_operand" "=r") + (match_dup 2))] "" " { - if (GET_CODE (operands[0]) == CONST_INT - && INTVAL (operands[0]) < 32768) + if (GET_CODE (operands[1]) == CONST_INT + && INTVAL (operands[1]) < 32768) { - if (INTVAL (operands[0]) >= 4096) + if (INTVAL (operands[1]) >= 4096) { /* We do this the same way as in the prologue and generate explicit probes. Then we update the stack by the constant. */ @@ -3721,14 +5018,15 @@ int probed = 4096; emit_insn (gen_probe_stack (GEN_INT (- probed))); - while (probed + 8192 < INTVAL (operands[0])) + while (probed + 8192 < INTVAL (operands[1])) emit_insn (gen_probe_stack (GEN_INT (- (probed += 8192)))); - if (probed + 4096 < INTVAL (operands[0])) - emit_insn (gen_probe_stack (GEN_INT (- INTVAL(operands[0])))); + if (probed + 4096 < INTVAL (operands[1])) + emit_insn (gen_probe_stack (GEN_INT (- INTVAL(operands[1])))); } - operands[0] = GEN_INT (- INTVAL (operands[0])); + operands[1] = GEN_INT (- INTVAL (operands[1])); + operands[2] = virtual_stack_dynamic_rtx; } else { @@ -3739,10 +5037,10 @@ rtx memref; emit_insn (gen_subdi3 (want, stack_pointer_rtx, - force_reg (Pmode, operands[0]))); + force_reg (Pmode, operands[1]))); emit_insn (gen_adddi3 (tmp, stack_pointer_rtx, GEN_INT (-4096))); - if (GET_CODE (operands[0]) != CONST_INT) + if (GET_CODE (operands[1]) != CONST_INT) { out_label = gen_label_rtx (); emit_insn (gen_cmpdi (want, tmp)); @@ -3750,13 +5048,16 @@ } emit_label (loop_label); - memref = gen_rtx (MEM, DImode, tmp); + memref = gen_rtx_MEM (DImode, tmp); MEM_VOLATILE_P (memref) = 1; emit_move_insn (memref, const0_rtx); emit_insn (gen_adddi3 (tmp, tmp, GEN_INT(-8192))); emit_insn (gen_cmpdi (tmp, want)); emit_jump_insn (gen_bgtu (loop_label)); - memref = gen_rtx (MEM, DImode, want); + if (obey_regdecls) + gen_rtx_USE (VOIDmode, tmp); + + memref = gen_rtx_MEM (DImode, want); MEM_VOLATILE_P (memref) = 1; emit_move_insn (memref, const0_rtx); @@ -3764,7 +5065,160 @@ emit_label (out_label); emit_move_insn (stack_pointer_rtx, want); - + emit_move_insn (operands[0], virtual_stack_dynamic_rtx); DONE; } }") + +;; This is used by alpha_expand_prolog to do the same thing as above, +;; except we cannot at that time generate new basic blocks, so we hide +;; the loop in this one insn. + +(define_insn "prologue_stack_probe_loop" + [(unspec_volatile [(match_operand 0 "register_operand" "r") + (match_operand 1 "register_operand" "r")] 5)] + "" + "* +{ + static int label_no; + int count_regno = REGNO (operands[0]); + int ptr_regno = REGNO (operands[1]); + char label[64]; + + /* Ho hum, output the hard way to get the label at the beginning of + the line. Wish there were a magic char you could get + asm_output_printf to do that. Then we could use %= as well and + get rid of the label_no bits here too. */ + + ASM_GENERATE_INTERNAL_LABEL (label, \"LSC\", label_no); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LSC\", label_no++); + + fprintf (asm_out_file, \"\\tstq $31,-8192($%d)\\n\", ptr_regno); + fprintf (asm_out_file, \"\\tsubq $%d,1,$%d\\n\", count_regno, count_regno); + fprintf (asm_out_file, \"\\tlda $%d,-8192($%d)\\n\", ptr_regno, ptr_regno); + fprintf (asm_out_file, \"\\tbne $%d,\", count_regno); + assemble_name (asm_out_file, label); + putc ('\\n', asm_out_file); + + return \"\"; +}" + [(set_attr "length" "16")]) + +(define_expand "prologue" + [(clobber (const_int 0))] + "" + "alpha_expand_prologue (); DONE;") + +(define_insn "init_fp" + [(set (match_operand:DI 0 "register_operand" "r") + (match_operand:DI 1 "register_operand" "r")) + (clobber (mem:BLK (match_operand:DI 2 "register_operand" "r")))] + "" + "bis %1,%1,%0") + +(define_expand "epilogue" + [(clobber (const_int 0))] + "" + "alpha_expand_epilogue (); DONE;") + +(define_expand "builtin_longjmp" + [(unspec_volatile [(match_operand 0 "register_operand" "r")] 3)] + "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT" + " +{ + /* The elements of the buffer are, in order: */ + rtx fp = gen_rtx_MEM (Pmode, operands[0]); + rtx lab = gen_rtx_MEM (Pmode, plus_constant (operands[0], 8)); + rtx stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 16)); + rtx pv = gen_rtx_REG (Pmode, 27); + + /* This bit is the same as expand_builtin_longjmp. */ + emit_move_insn (hard_frame_pointer_rtx, fp); + emit_move_insn (pv, lab); + emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX); + emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); + emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); + + /* Load the label we are jumping through into $27 so that we know + where to look for it when we get back to setjmp's function for + restoring the gp. */ + emit_indirect_jump (pv); +}") + +(define_insn "builtin_setjmp_receiver" + [(unspec_volatile [(match_operand 0 "" "")] 2)] + "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT && TARGET_AS_CAN_SUBTRACT_LABELS" + "\\n$LSJ%=:\;ldgp $29,$LSJ%=-%l0($27)" + [(set_attr "length" "8")]) + +(define_insn "" + [(unspec_volatile [(match_operand 0 "" "")] 2)] + "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT" + "br $27,$LSJ%=\\n$LSJ%=:\;ldgp $29,0($27)" + [(set_attr "length" "12")]) + +(define_expand "nonlocal_goto_receiver" + [(unspec_volatile [(const_int 0)] 1) + (set (reg:DI 27) (mem:DI (reg:DI 29))) + (unspec_volatile [(const_int 0)] 1) + (use (reg:DI 27))] + "TARGET_OPEN_VMS" + "") + +(define_insn "arg_home" + [(unspec [(const_int 0)] 0) + (use (reg:DI 1)) + (use (reg:DI 25)) + (use (reg:DI 16)) + (use (reg:DI 17)) + (use (reg:DI 18)) + (use (reg:DI 19)) + (use (reg:DI 20)) + (use (reg:DI 21)) + (use (reg:DI 48)) + (use (reg:DI 49)) + (use (reg:DI 50)) + (use (reg:DI 51)) + (use (reg:DI 52)) + (use (reg:DI 53)) + (clobber (mem:BLK (const_int 0))) + (clobber (reg:DI 24)) + (clobber (reg:DI 25)) + (clobber (reg:DI 0))] + "TARGET_OPEN_VMS" + "lda $0,OTS$HOME_ARGS\;ldq $0,8($0)\;jsr $0,OTS$HOME_ARGS" + [(set_attr "length" "16")]) + +;; Close the trap shadow of preceeding instructions. This is generated +;; by alpha_reorg. + +(define_insn "trapb" + [(unspec_volatile [(const_int 0)] 4)] + "" + "trapb" + [(set_attr "type" "misc")]) + +;; Peepholes go at the end. + +;; Optimize sign-extension of SImode loads. This shows up in the wake of +;; reload when converting fp->int. +;; +;; ??? What to do now that we actually care about the packing and +;; alignment of instructions? Perhaps reload can be enlightened, or +;; the peephole pass moved up after reload but before sched2? +; +;(define_peephole +; [(set (match_operand:SI 0 "register_operand" "=r") +; (match_operand:SI 1 "memory_operand" "m")) +; (set (match_operand:DI 2 "register_operand" "=r") +; (sign_extend:DI (match_dup 0)))] +; "dead_or_set_p (insn, operands[0])" +; "ldl %2,%1") +; +;(define_peephole +; [(set (match_operand:SI 0 "register_operand" "=r") +; (match_operand:SI 1 "hard_fp_register_operand" "f")) +; (set (match_operand:DI 2 "register_operand" "=r") +; (sign_extend:DI (match_dup 0)))] +; "TARGET_CIX && dead_or_set_p (insn, operands[0])" +; "ftois %1,%2") |