diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /gcc/config/alpha/alpha.md | |
download | cbb-gcc-4.6.4-upstream.tar.bz2 cbb-gcc-4.6.4-upstream.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'gcc/config/alpha/alpha.md')
-rw-r--r-- | gcc/config/alpha/alpha.md | 7999 |
1 files changed, 7999 insertions, 0 deletions
diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md new file mode 100644 index 000000000..d6fba76f7 --- /dev/null +++ b/gcc/config/alpha/alpha.md @@ -0,0 +1,7999 @@ +;; Machine description for DEC Alpha for GNU C compiler +;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +;; 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 +;; Free Software Foundation, Inc. +;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; <http://www.gnu.org/licenses/>. + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;; Uses of UNSPEC in this file: + +(define_constants + [(UNSPEC_ARG_HOME 0) + (UNSPEC_LDGP1 1) + (UNSPEC_INSXH 2) + (UNSPEC_MSKXH 3) + (UNSPEC_CVTQL 4) + (UNSPEC_CVTLQ 5) + (UNSPEC_UMK_LAUM 6) + (UNSPEC_UMK_LALM 7) + (UNSPEC_UMK_LAL 8) + (UNSPEC_UMK_LOAD_CIW 9) + (UNSPEC_LDGP2 10) + (UNSPEC_LITERAL 11) + (UNSPEC_LITUSE 12) + (UNSPEC_SIBCALL 13) + (UNSPEC_SYMBOL 14) + + ;; TLS Support + (UNSPEC_TLSGD_CALL 15) + (UNSPEC_TLSLDM_CALL 16) + (UNSPEC_TLSGD 17) + (UNSPEC_TLSLDM 18) + (UNSPEC_DTPREL 19) + (UNSPEC_TPREL 20) + (UNSPEC_TP 21) + + ;; Builtins + (UNSPEC_CMPBGE 22) + (UNSPEC_ZAP 23) + (UNSPEC_AMASK 24) + (UNSPEC_IMPLVER 25) + (UNSPEC_PERR 26) + (UNSPEC_COPYSIGN 27) + + ;; Atomic operations + (UNSPEC_MB 28) + (UNSPEC_ATOMIC 31) + (UNSPEC_CMPXCHG 32) + (UNSPEC_XCHG 33) + ]) + +;; UNSPEC_VOLATILE: + +(define_constants + [(UNSPECV_IMB 0) + (UNSPECV_BLOCKAGE 1) + (UNSPECV_SETJMPR 2) ; builtin_setjmp_receiver + (UNSPECV_LONGJMP 3) ; builtin_longjmp + (UNSPECV_TRAPB 4) + (UNSPECV_PSPL 5) ; prologue_stack_probe_loop + (UNSPECV_REALIGN 6) + (UNSPECV_EHR 7) ; exception_receiver + (UNSPECV_MCOUNT 8) + (UNSPECV_FORCE_MOV 9) + (UNSPECV_LDGP1 10) + (UNSPECV_PLDGP2 11) ; prologue ldgp + (UNSPECV_SET_TP 12) + (UNSPECV_RPCC 13) + (UNSPECV_SETJMPR_ER 14) ; builtin_setjmp_receiver fragment + (UNSPECV_LL 15) ; load-locked + (UNSPECV_SC 16) ; store-conditional + ]) + +;; On non-BWX targets, CQImode must be handled the similarly to HImode +;; when generating reloads. +(define_mode_iterator RELOAD12 [QI HI CQI]) +(define_mode_attr reloadmode [(QI "qi") (HI "hi") (CQI "hi")]) + +;; Other mode iterators +(define_mode_iterator I12MODE [QI HI]) +(define_mode_iterator I48MODE [SI DI]) +(define_mode_attr modesuffix [(SI "l") (DI "q")]) + +;; Where necessary, the suffixes _le and _be are used to distinguish between +;; little-endian and big-endian patterns. +;; +;; Note that the Unicos/Mk assembler does not support the following +;; opcodes: mov, fmov, nop, fnop, unop. + +;; Processor type -- this attribute must exactly match the processor_type +;; enumeration in alpha.h. + +(define_attr "tune" "ev4,ev5,ev6" + (const (symbol_ref "((enum attr_tune) alpha_tune)"))) + +;; 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" + "ild,fld,ldsym,ist,fst,ibr,callpal,fbr,jsr,iadd,ilog,shift,icmov,fcmov, + icmp,imul,fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,mb,ld_l,st_c, + multi,none" + (const_string "iadd")) + +;; Describe a user's asm statement. +(define_asm_attributes + [(set_attr "type" "multi")]) + +;; Define the operand size an insn operates on. Used primarily by mul +;; and div operations that have size dependent timings. + +(define_attr "opsize" "si,di,udi" + (const_string "di")) + +;; The TRAP attribute marks instructions that may generate traps +;; (which are imprecise and may need a trapb if software completion +;; is desired). + +(define_attr "trap" "no,yes" + (const_string "no")) + +;; The ROUND_SUFFIX attribute marks which instructions require a +;; rounding-mode suffix. The value NONE indicates no suffix, +;; the value NORMAL indicates a suffix controlled by alpha_fprm. + +(define_attr "round_suffix" "none,normal,c" + (const_string "none")) + +;; The TRAP_SUFFIX attribute marks instructions requiring a trap-mode suffix: +;; NONE no suffix +;; SU accepts only /su (cmpt et al) +;; SUI accepts only /sui (cvtqt and cvtqs) +;; V_SV accepts /v and /sv (cvtql only) +;; V_SV_SVI accepts /v, /sv and /svi (cvttq only) +;; U_SU_SUI accepts /u, /su and /sui (most fp instructions) +;; +;; The actual suffix emitted is controlled by alpha_fptm. + +(define_attr "trap_suffix" "none,su,sui,v_sv,v_sv_svi,u_su_sui" + (const_string "none")) + +;; The length of an instruction sequence in bytes. + +(define_attr "length" "" + (const_int 4)) + +;; The USEGP attribute marks instructions that have relocations that use +;; the GP. + +(define_attr "usegp" "no,yes" + (cond [(eq_attr "type" "ldsym,jsr") + (const_string "yes") + (eq_attr "type" "ild,fld,ist,fst") + (symbol_ref "((enum attr_usegp) alpha_find_lo_sum_using_gp (insn))") + ] + (const_string "no"))) + +;; The CANNOT_COPY attribute marks instructions with relocations that +;; cannot easily be duplicated. This includes insns with gpdisp relocs +;; since they have to stay in 1-1 correspondence with one another. This +;; also includes jsr insns, since they must stay in correspondence with +;; the immediately following gpdisp instructions. + +(define_attr "cannot_copy" "false,true" + (const_string "false")) + +;; Include scheduling descriptions. + +(include "ev4.md") +(include "ev5.md") +(include "ev6.md") + + +;; Operand and operator predicates and constraints + +(include "predicates.md") +(include "constraints.md") + + +;; First define the arithmetic insns. Note that the 32-bit forms also +;; sign-extend. + +;; Handle 32-64 bit extension from memory to a floating point register +;; specially, since this occurs frequently in int->double conversions. +;; +;; 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_expand "extendsidi2" + [(set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))] + "" + "") + +(define_insn "*cvtlq" + [(set (match_operand:DI 0 "register_operand" "=f") + (unspec:DI [(match_operand:SF 1 "reg_or_0_operand" "fG")] + UNSPEC_CVTLQ))] + "" + "cvtlq %1,%0" + [(set_attr "type" "fadd")]) + +(define_insn "*extendsidi2_1" + [(set (match_operand:DI 0 "register_operand" "=r,r,!*f") + (sign_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "r,m,m")))] + "" + "@ + addl $31,%1,%0 + ldl %0,%1 + lds %0,%1\;cvtlq %0,%0" + [(set_attr "type" "iadd,ild,fld") + (set_attr "length" "*,*,8")]) + +(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)] UNSPEC_CVTLQ))] +{ + operands[1] = adjust_address (operands[1], SFmode, 0); + operands[2] = gen_rtx_REG (SFmode, REGNO (operands[0])); +}) + +;; Optimize sign-extension of SImode loads. This shows up in the wake of +;; reload when converting fp->int. + +(define_peephole2 + [(set (match_operand:SI 0 "hard_int_register_operand" "") + (match_operand:SI 1 "memory_operand" "")) + (set (match_operand:DI 2 "hard_int_register_operand" "") + (sign_extend:DI (match_dup 0)))] + "true_regnum (operands[0]) == true_regnum (operands[2]) + || peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) + (sign_extend:DI (match_dup 1)))] + "") + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") + (plus:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ,rJ,rJ") + (match_operand:SI 2 "add_operand" "rI,O,K,L")))] + "" + "@ + addl %r1,%2,%0 + subl %r1,%n2,%0 + lda %0,%2(%r1) + ldah %0,%h2(%r1)") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "! add_operand (operands[2], SImode)" + [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3))) + (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))] +{ + HOST_WIDE_INT val = INTVAL (operands[2]); + HOST_WIDE_INT low = (val & 0xffff) - 2 * (val & 0x8000); + HOST_WIDE_INT rest = val - low; + + operands[3] = GEN_INT (rest); + operands[4] = GEN_INT (low); +}) + +(define_insn "*addsi_se" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (sign_extend:DI + (plus:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ") + (match_operand:SI 2 "sext_add_operand" "rI,O"))))] + "" + "@ + addl %r1,%2,%0 + subl %r1,%n2,%0") + +(define_insn "*addsi_se2" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (sign_extend:DI + (subreg:SI (plus:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ,rJ") + (match_operand:DI 2 "sext_add_operand" "rI,O")) + 0)))] + "" + "@ + addl %r1,%2,%0 + subl %r1,%n2,%0") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI + (plus:SI (match_operand:SI 1 "reg_not_elim_operand" "") + (match_operand:SI 2 "const_int_operand" "")))) + (clobber (match_operand:SI 3 "reg_not_elim_operand" ""))] + "! sext_add_operand (operands[2], SImode) && INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) % 4 == 0" + [(set (match_dup 3) (match_dup 4)) + (set (match_dup 0) (sign_extend:DI (plus:SI (mult:SI (match_dup 3) + (match_dup 5)) + (match_dup 1))))] +{ + HOST_WIDE_INT val = INTVAL (operands[2]) / 4; + int mult = 4; + + if (val % 2 == 0) + val /= 2, mult = 8; + + operands[4] = GEN_INT (val); + operands[5] = GEN_INT (mult); +}) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI + (plus:SI (match_operator:SI 1 "comparison_operator" + [(match_operand 2 "" "") + (match_operand 3 "" "")]) + (match_operand:SI 4 "add_operand" "")))) + (clobber (match_operand:DI 5 "register_operand" ""))] + "" + [(set (match_dup 5) (match_dup 6)) + (set (match_dup 0) (sign_extend:DI (plus:SI (match_dup 7) (match_dup 4))))] +{ + operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[1]), DImode, + operands[2], operands[3]); + operands[7] = gen_lowpart (SImode, operands[5]); +}) + +(define_insn "addvsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (plus:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ") + (match_operand:SI 2 "sext_add_operand" "rI,O"))) + (trap_if (ne (plus:DI (sign_extend:DI (match_dup 1)) + (sign_extend:DI (match_dup 2))) + (sign_extend:DI (plus:SI (match_dup 1) + (match_dup 2)))) + (const_int 0))] + "" + "@ + addlv %r1,%2,%0 + sublv %r1,%n2,%0") + +(define_expand "adddi3" + [(set (match_operand:DI 0 "register_operand" "") + (plus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "add_operand" "")))] + "" + "") + +(define_insn "*adddi_er_lo16_dtp" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "dtp16_symbolic_operand" "")))] + "HAVE_AS_TLS" + "lda %0,%2(%1)\t\t!dtprel") + +(define_insn "*adddi_er_hi32_dtp" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (match_operand:DI 1 "register_operand" "r") + (high:DI (match_operand:DI 2 "dtp32_symbolic_operand" ""))))] + "HAVE_AS_TLS" + "ldah %0,%2(%1)\t\t!dtprelhi") + +(define_insn "*adddi_er_lo32_dtp" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "dtp32_symbolic_operand" "")))] + "HAVE_AS_TLS" + "lda %0,%2(%1)\t\t!dtprello") + +(define_insn "*adddi_er_lo16_tp" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "tp16_symbolic_operand" "")))] + "HAVE_AS_TLS" + "lda %0,%2(%1)\t\t!tprel") + +(define_insn "*adddi_er_hi32_tp" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (match_operand:DI 1 "register_operand" "r") + (high:DI (match_operand:DI 2 "tp32_symbolic_operand" ""))))] + "HAVE_AS_TLS" + "ldah %0,%2(%1)\t\t!tprelhi") + +(define_insn "*adddi_er_lo32_tp" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "tp32_symbolic_operand" "")))] + "HAVE_AS_TLS" + "lda %0,%2(%1)\t\t!tprello") + +(define_insn "*adddi_er_high_l" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (match_operand:DI 1 "register_operand" "r") + (high:DI (match_operand:DI 2 "local_symbolic_operand" ""))))] + "TARGET_EXPLICIT_RELOCS && reload_completed" + "ldah %0,%2(%1)\t\t!gprelhigh" + [(set_attr "usegp" "yes")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (high:DI (match_operand:DI 1 "local_symbolic_operand" "")))] + "TARGET_EXPLICIT_RELOCS && reload_completed" + [(set (match_dup 0) + (plus:DI (match_dup 2) (high:DI (match_dup 1))))] + "operands[2] = pic_offset_table_rtx;") + +;; We used to expend quite a lot of effort choosing addq/subq/lda. +;; With complications like +;; +;; The NT stack unwind code can't handle a subq to adjust the stack +;; (that's a bug, but not one we can do anything about). As of NT4.0 SP3, +;; the exception handling code will loop if a subq is used and an +;; exception occurs. +;; +;; The 19980616 change to emit prologues as RTL also confused some +;; versions of GDB, which also interprets prologues. This has been +;; fixed as of GDB 4.18, but it does not harm to unconditionally +;; use lda here. +;; +;; and the fact that the three insns schedule exactly the same, it's +;; just not worth the effort. + +(define_insn "*adddi_internal" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (plus:DI (match_operand:DI 1 "register_operand" "%r,r,r") + (match_operand:DI 2 "add_operand" "r,K,L")))] + "" + "@ + addq %1,%2,%0 + lda %0,%2(%1) + ldah %0,%h2(%1)") + +;; ??? Allow large constants when basing off the frame pointer or some +;; virtual register that may eliminate to the frame pointer. This is +;; done because register elimination offsets will change the hi/lo split, +;; and if we split before reload, we will require additional instructions. + +(define_insn "*adddi_fp_hack" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (plus:DI (match_operand:DI 1 "reg_no_subreg_operand" "r,r,r") + (match_operand:DI 2 "const_int_operand" "K,L,n")))] + "NONSTRICT_REG_OK_FP_BASE_P (operands[1]) + && INTVAL (operands[2]) >= 0 + /* This is the largest constant an lda+ldah pair can add, minus + an upper bound on the displacement between SP and AP during + register elimination. See INITIAL_ELIMINATION_OFFSET. */ + && INTVAL (operands[2]) + < (0x7fff8000 + - FIRST_PSEUDO_REGISTER * UNITS_PER_WORD + - ALPHA_ROUND(crtl->outgoing_args_size) + - (ALPHA_ROUND (get_frame_size () + + max_reg_num () * UNITS_PER_WORD + + crtl->args.pretend_args_size) + - crtl->args.pretend_args_size))" + "@ + lda %0,%2(%1) + ldah %0,%h2(%1) + #") + +;; Don't do this if we are adjusting SP since we don't want to do it +;; in two steps. Don't split FP sources for the reason listed above. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (plus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "const_int_operand" "")))] + "! add_operand (operands[2], DImode) + && operands[0] != stack_pointer_rtx + && operands[1] != frame_pointer_rtx + && operands[1] != arg_pointer_rtx" + [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 3))) + (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))] +{ + HOST_WIDE_INT val = INTVAL (operands[2]); + HOST_WIDE_INT low = (val & 0xffff) - 2 * (val & 0x8000); + HOST_WIDE_INT rest = val - low; + rtx rest_rtx = GEN_INT (rest); + + operands[4] = GEN_INT (low); + if (satisfies_constraint_L (rest_rtx)) + operands[3] = rest_rtx; + else if (can_create_pseudo_p ()) + { + operands[3] = gen_reg_rtx (DImode); + emit_move_insn (operands[3], operands[2]); + emit_insn (gen_adddi3 (operands[0], operands[1], operands[3])); + DONE; + } + else + FAIL; +}) + +(define_insn "*saddl" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (plus:SI (mult:SI (match_operand:SI 1 "reg_not_elim_operand" "r,r") + (match_operand:SI 2 "const48_operand" "I,I")) + (match_operand:SI 3 "sext_add_operand" "rI,O")))] + "" + "@ + s%2addl %1,%3,%0 + s%2subl %1,%n3,%0") + +(define_insn "*saddl_se" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (sign_extend:DI + (plus:SI (mult:SI (match_operand:SI 1 "reg_not_elim_operand" "r,r") + (match_operand:SI 2 "const48_operand" "I,I")) + (match_operand:SI 3 "sext_add_operand" "rI,O"))))] + "" + "@ + s%2addl %1,%3,%0 + s%2subl %1,%n3,%0") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (sign_extend:DI + (plus:SI (mult:SI (match_operator:SI 1 "comparison_operator" + [(match_operand 2 "" "") + (match_operand 3 "" "")]) + (match_operand:SI 4 "const48_operand" "")) + (match_operand:SI 5 "sext_add_operand" "")))) + (clobber (match_operand:DI 6 "reg_not_elim_operand" ""))] + "" + [(set (match_dup 6) (match_dup 7)) + (set (match_dup 0) + (sign_extend:DI (plus:SI (mult:SI (match_dup 8) (match_dup 4)) + (match_dup 5))))] +{ + operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[1]), DImode, + operands[2], operands[3]); + operands[8] = gen_lowpart (SImode, operands[6]); +}) + +(define_insn "*saddq" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (plus:DI (mult:DI (match_operand:DI 1 "reg_not_elim_operand" "r,r") + (match_operand:DI 2 "const48_operand" "I,I")) + (match_operand:DI 3 "sext_add_operand" "rI,O")))] + "" + "@ + s%2addq %1,%3,%0 + s%2subq %1,%n3,%0") + +(define_insn "addvdi3" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (plus:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ,rJ") + (match_operand:DI 2 "sext_add_operand" "rI,O"))) + (trap_if (ne (plus:TI (sign_extend:TI (match_dup 1)) + (sign_extend:TI (match_dup 2))) + (sign_extend:TI (plus:DI (match_dup 1) + (match_dup 2)))) + (const_int 0))] + "" + "@ + addqv %r1,%2,%0 + subqv %r1,%n2,%0") + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "reg_or_8bit_operand" "rI")))] + "" + "subl $31,%1,%0") + +(define_insn "*negsi_se" + [(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") + +(define_insn "negvsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "register_operand" "r"))) + (trap_if (ne (neg:DI (sign_extend:DI (match_dup 1))) + (sign_extend:DI (neg:SI (match_dup 1)))) + (const_int 0))] + "" + "sublv $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") + +(define_insn "negvdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (neg:DI (match_operand:DI 1 "register_operand" "r"))) + (trap_if (ne (neg:TI (sign_extend:TI (match_dup 1))) + (sign_extend:TI (neg:DI (match_dup 1)))) + (const_int 0))] + "" + "subqv $31,%1,%0") + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ") + (match_operand:SI 2 "reg_or_8bit_operand" "rI")))] + "" + "subl %r1,%2,%0") + +(define_insn "*subsi_se" + [(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") + +(define_insn "*subsi_se2" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (subreg:SI (minus:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (match_operand:DI 2 "reg_or_8bit_operand" "rI")) + 0)))] + "" + "subl %r1,%2,%0") + +(define_insn "subvsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ") + (match_operand:SI 2 "reg_or_8bit_operand" "rI"))) + (trap_if (ne (minus:DI (sign_extend:DI (match_dup 1)) + (sign_extend:DI (match_dup 2))) + (sign_extend:DI (minus:SI (match_dup 1) + (match_dup 2)))) + (const_int 0))] + "" + "sublv %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") + +(define_insn "*ssubl" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (mult:SI (match_operand:SI 1 "reg_not_elim_operand" "r") + (match_operand:SI 2 "const48_operand" "I")) + (match_operand:SI 3 "reg_or_8bit_operand" "rI")))] + "" + "s%2subl %1,%3,%0") + +(define_insn "*ssubl_se" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (minus:SI (mult:SI (match_operand:SI 1 "reg_not_elim_operand" "r") + (match_operand:SI 2 "const48_operand" "I")) + (match_operand:SI 3 "reg_or_8bit_operand" "rI"))))] + "" + "s%2subl %1,%3,%0") + +(define_insn "*ssubq" + [(set (match_operand:DI 0 "register_operand" "=r") + (minus:DI (mult:DI (match_operand:DI 1 "reg_not_elim_operand" "r") + (match_operand:DI 2 "const48_operand" "I")) + (match_operand:DI 3 "reg_or_8bit_operand" "rI")))] + "" + "s%2subq %1,%3,%0") + +(define_insn "subvdi3" + [(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"))) + (trap_if (ne (minus:TI (sign_extend:TI (match_dup 1)) + (sign_extend:TI (match_dup 2))) + (sign_extend:TI (minus:DI (match_dup 1) + (match_dup 2)))) + (const_int 0))] + "" + "subqv %r1,%2,%0") + +;; The Unicos/Mk assembler doesn't support mull. + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ") + (match_operand:SI 2 "reg_or_8bit_operand" "rI")))] + "!TARGET_ABI_UNICOSMK" + "mull %r1,%2,%0" + [(set_attr "type" "imul") + (set_attr "opsize" "si")]) + +(define_insn "*mulsi_se" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (mult:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ") + (match_operand:SI 2 "reg_or_8bit_operand" "rI"))))] + "!TARGET_ABI_UNICOSMK" + "mull %r1,%2,%0" + [(set_attr "type" "imul") + (set_attr "opsize" "si")]) + +(define_insn "mulvsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (mult:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ") + (match_operand:SI 2 "reg_or_8bit_operand" "rI"))) + (trap_if (ne (mult:DI (sign_extend:DI (match_dup 1)) + (sign_extend:DI (match_dup 2))) + (sign_extend:DI (mult:SI (match_dup 1) + (match_dup 2)))) + (const_int 0))] + "!TARGET_ABI_UNICOSMK" + "mullv %r1,%2,%0" + [(set_attr "type" "imul") + (set_attr "opsize" "si")]) + +(define_insn "muldi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (mult:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ") + (match_operand:DI 2 "reg_or_8bit_operand" "rI")))] + "" + "mulq %r1,%2,%0" + [(set_attr "type" "imul")]) + +(define_insn "mulvdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (mult:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ") + (match_operand:DI 2 "reg_or_8bit_operand" "rI"))) + (trap_if (ne (mult:TI (sign_extend:TI (match_dup 1)) + (sign_extend:TI (match_dup 2))) + (sign_extend:TI (mult:DI (match_dup 1) + (match_dup 2)))) + (const_int 0))] + "" + "mulqv %r1,%2,%0" + [(set_attr "type" "imul")]) + +(define_expand "umuldi3_highpart" + [(set (match_operand:DI 0 "register_operand" "") + (truncate:DI + (lshiftrt:TI + (mult:TI (zero_extend:TI + (match_operand:DI 1 "register_operand" "")) + (match_operand:DI 2 "reg_or_8bit_operand" "")) + (const_int 64))))] + "" +{ + if (REG_P (operands[2])) + operands[2] = gen_rtx_ZERO_EXTEND (TImode, operands[2]); +}) + +(define_insn "*umuldi3_highpart_reg" + [(set (match_operand:DI 0 "register_operand" "=r") + (truncate:DI + (lshiftrt:TI + (mult:TI (zero_extend:TI + (match_operand:DI 1 "register_operand" "r")) + (zero_extend:TI + (match_operand:DI 2 "register_operand" "r"))) + (const_int 64))))] + "" + "umulh %1,%2,%0" + [(set_attr "type" "imul") + (set_attr "opsize" "udi")]) + +(define_insn "*umuldi3_highpart_const" + [(set (match_operand:DI 0 "register_operand" "=r") + (truncate:DI + (lshiftrt:TI + (mult:TI (zero_extend:TI (match_operand:DI 1 "register_operand" "r")) + (match_operand:TI 2 "cint8_operand" "I")) + (const_int 64))))] + "" + "umulh %1,%2,%0" + [(set_attr "type" "imul") + (set_attr "opsize" "udi")]) + +;; The divide and remainder operations take their inputs from r24 and +;; r25, put their output in r27, and clobber r23 and r28 on all +;; systems except Unicos/Mk. On Unicos, the standard library provides +;; subroutines which use the standard calling convention and work on +;; DImode operands. + +;; ??? Force sign-extension here because some versions of OSF/1 and +;; Interix/NT 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 (match_dup 3) + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" ""))) + (set (match_dup 4) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" ""))) + (parallel [(set (match_dup 5) + (sign_extend:DI (div:SI (match_dup 3) (match_dup 4)))) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))]) + (set (match_operand:SI 0 "nonimmediate_operand" "") + (subreg:SI (match_dup 5) 0))] + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" +{ + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); + operands[5] = gen_reg_rtx (DImode); +}) + +(define_expand "udivsi3" + [(set (match_dup 3) + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" ""))) + (set (match_dup 4) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" ""))) + (parallel [(set (match_dup 5) + (sign_extend:DI (udiv:SI (match_dup 3) (match_dup 4)))) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))]) + (set (match_operand:SI 0 "nonimmediate_operand" "") + (subreg:SI (match_dup 5) 0))] + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" +{ + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); + operands[5] = gen_reg_rtx (DImode); +}) + +(define_expand "modsi3" + [(set (match_dup 3) + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" ""))) + (set (match_dup 4) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" ""))) + (parallel [(set (match_dup 5) + (sign_extend:DI (mod:SI (match_dup 3) (match_dup 4)))) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))]) + (set (match_operand:SI 0 "nonimmediate_operand" "") + (subreg:SI (match_dup 5) 0))] + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" +{ + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); + operands[5] = gen_reg_rtx (DImode); +}) + +(define_expand "umodsi3" + [(set (match_dup 3) + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" ""))) + (set (match_dup 4) + (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" ""))) + (parallel [(set (match_dup 5) + (sign_extend:DI (umod:SI (match_dup 3) (match_dup 4)))) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))]) + (set (match_operand:SI 0 "nonimmediate_operand" "") + (subreg:SI (match_dup 5) 0))] + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" +{ + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); + operands[5] = gen_reg_rtx (DImode); +}) + +(define_expand "divdi3" + [(parallel [(set (match_operand:DI 0 "register_operand" "") + (div:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" ""))) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))])] + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" + "") + +(define_expand "udivdi3" + [(parallel [(set (match_operand:DI 0 "register_operand" "") + (udiv:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" ""))) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))])] + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" + "") + +(define_expand "moddi3" + [(use (match_operand:DI 0 "register_operand" "")) + (use (match_operand:DI 1 "register_operand" "")) + (use (match_operand:DI 2 "register_operand" ""))] + "!TARGET_ABI_OPEN_VMS" +{ + if (TARGET_ABI_UNICOSMK) + emit_insn (gen_moddi3_umk (operands[0], operands[1], operands[2])); + else + emit_insn (gen_moddi3_dft (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_expand "moddi3_dft" + [(parallel [(set (match_operand:DI 0 "register_operand" "") + (mod:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" ""))) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))])] + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" + "") + +;; On Unicos/Mk, we do as the system's C compiler does: +;; compute the quotient, multiply and subtract. + +(define_expand "moddi3_umk" + [(use (match_operand:DI 0 "register_operand" "")) + (use (match_operand:DI 1 "register_operand" "")) + (use (match_operand:DI 2 "register_operand" ""))] + "TARGET_ABI_UNICOSMK" +{ + rtx div, mul = gen_reg_rtx (DImode); + + div = expand_binop (DImode, sdiv_optab, operands[1], operands[2], + NULL_RTX, 0, OPTAB_LIB); + div = force_reg (DImode, div); + emit_insn (gen_muldi3 (mul, operands[2], div)); + emit_insn (gen_subdi3 (operands[0], operands[1], mul)); + DONE; +}) + +(define_expand "umoddi3" + [(use (match_operand:DI 0 "register_operand" "")) + (use (match_operand:DI 1 "register_operand" "")) + (use (match_operand:DI 2 "register_operand" ""))] + "! TARGET_ABI_OPEN_VMS" +{ + if (TARGET_ABI_UNICOSMK) + emit_insn (gen_umoddi3_umk (operands[0], operands[1], operands[2])); + else + emit_insn (gen_umoddi3_dft (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_expand "umoddi3_dft" + [(parallel [(set (match_operand:DI 0 "register_operand" "") + (umod:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "register_operand" ""))) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))])] + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" + "") + +(define_expand "umoddi3_umk" + [(use (match_operand:DI 0 "register_operand" "")) + (use (match_operand:DI 1 "register_operand" "")) + (use (match_operand:DI 2 "register_operand" ""))] + "TARGET_ABI_UNICOSMK" +{ + rtx div, mul = gen_reg_rtx (DImode); + + div = expand_binop (DImode, udiv_optab, operands[1], operands[2], + NULL_RTX, 1, OPTAB_LIB); + div = force_reg (DImode, div); + emit_insn (gen_muldi3 (mul, operands[2], div)); + emit_insn (gen_subdi3 (operands[0], operands[1], mul)); + DONE; +}) + +;; Lengths of 8 for ldq $t12,__divq($gp); jsr $t9,($t12),__divq as +;; expanded by the assembler. + +(define_insn_and_split "*divmodsi_internal_er" + [(set (match_operand:DI 0 "register_operand" "=c") + (sign_extend:DI (match_operator:SI 3 "divmod_operator" + [(match_operand:DI 1 "register_operand" "a") + (match_operand:DI 2 "register_operand" "b")]))) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))] + "TARGET_EXPLICIT_RELOCS && ! TARGET_ABI_OPEN_VMS" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) + (sign_extend:DI (match_dup 3))) + (use (match_dup 0)) + (use (match_dup 4)) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))])] +{ + const char *str; + switch (GET_CODE (operands[3])) + { + case DIV: + str = "__divl"; + break; + case UDIV: + str = "__divlu"; + break; + case MOD: + str = "__reml"; + break; + case UMOD: + str = "__remlu"; + break; + default: + gcc_unreachable (); + } + operands[4] = GEN_INT (alpha_next_sequence_number++); + emit_insn (gen_movdi_er_high_g (operands[0], pic_offset_table_rtx, + gen_rtx_SYMBOL_REF (DImode, str), + operands[4])); +} + [(set_attr "type" "jsr") + (set_attr "length" "8")]) + +(define_insn "*divmodsi_internal_er_1" + [(set (match_operand:DI 0 "register_operand" "=c") + (sign_extend:DI (match_operator:SI 3 "divmod_operator" + [(match_operand:DI 1 "register_operand" "a") + (match_operand:DI 2 "register_operand" "b")]))) + (use (match_operand:DI 4 "register_operand" "c")) + (use (match_operand 5 "const_int_operand" "")) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))] + "TARGET_EXPLICIT_RELOCS && ! TARGET_ABI_OPEN_VMS" + "jsr $23,($27),__%E3%j5" + [(set_attr "type" "jsr") + (set_attr "length" "4")]) + +(define_insn "*divmodsi_internal" + [(set (match_operand:DI 0 "register_operand" "=c") + (sign_extend:DI (match_operator:SI 3 "divmod_operator" + [(match_operand:DI 1 "register_operand" "a") + (match_operand:DI 2 "register_operand" "b")]))) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))] + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" + "%E3 %1,%2,%0" + [(set_attr "type" "jsr") + (set_attr "length" "8")]) + +(define_insn_and_split "*divmoddi_internal_er" + [(set (match_operand:DI 0 "register_operand" "=c") + (match_operator:DI 3 "divmod_operator" + [(match_operand:DI 1 "register_operand" "a") + (match_operand:DI 2 "register_operand" "b")])) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))] + "TARGET_EXPLICIT_RELOCS && ! TARGET_ABI_OPEN_VMS" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) (match_dup 3)) + (use (match_dup 0)) + (use (match_dup 4)) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))])] +{ + const char *str; + switch (GET_CODE (operands[3])) + { + case DIV: + str = "__divq"; + break; + case UDIV: + str = "__divqu"; + break; + case MOD: + str = "__remq"; + break; + case UMOD: + str = "__remqu"; + break; + default: + gcc_unreachable (); + } + operands[4] = GEN_INT (alpha_next_sequence_number++); + emit_insn (gen_movdi_er_high_g (operands[0], pic_offset_table_rtx, + gen_rtx_SYMBOL_REF (DImode, str), + operands[4])); +} + [(set_attr "type" "jsr") + (set_attr "length" "8")]) + +(define_insn "*divmoddi_internal_er_1" + [(set (match_operand:DI 0 "register_operand" "=c") + (match_operator:DI 3 "divmod_operator" + [(match_operand:DI 1 "register_operand" "a") + (match_operand:DI 2 "register_operand" "b")])) + (use (match_operand:DI 4 "register_operand" "c")) + (use (match_operand 5 "const_int_operand" "")) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))] + "TARGET_EXPLICIT_RELOCS && ! TARGET_ABI_OPEN_VMS" + "jsr $23,($27),__%E3%j5" + [(set_attr "type" "jsr") + (set_attr "length" "4")]) + +(define_insn "*divmoddi_internal" + [(set (match_operand:DI 0 "register_operand" "=c") + (match_operator:DI 3 "divmod_operator" + [(match_operand:DI 1 "register_operand" "a") + (match_operand:DI 2 "register_operand" "b")])) + (clobber (reg:DI 23)) + (clobber (reg:DI 28))] + "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK" + "%E3 %1,%2,%0" + [(set_attr "type" "jsr") + (set_attr "length" "8")]) + +;; Next are the basic logical operations. We only expose the DImode operations +;; to the rtl expanders, but SImode versions exist for combine as well as for +;; the atomic operation splitters. + +(define_insn "*andsi_internal" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (and:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ,rJ") + (match_operand:SI 2 "and_operand" "rI,N,MH")))] + "" + "@ + and %r1,%2,%0 + bic %r1,%N2,%0 + zapnot %r1,%m2,%0" + [(set_attr "type" "ilog,ilog,shift")]) + +(define_insn "anddi3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r") + (and:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ,rJ,rJ") + (match_operand:DI 2 "and_operand" "rI,N,MH")))] + "" + "@ + and %r1,%2,%0 + bic %r1,%N2,%0 + zapnot %r1,%m2,%0" + [(set_attr "type" "ilog,ilog,shift")]) + +;; 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 do this when running on 64-bit host since the computations are +;; too messy otherwise. + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (and:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "const_int_operand" "")))] + "HOST_BITS_PER_WIDE_INT == 64 && ! and_operand (operands[2], DImode)" + [(set (match_dup 0) (and:DI (match_dup 1) (match_dup 3))) + (set (match_dup 0) (and:DI (match_dup 0) (match_dup 4)))] +{ + unsigned HOST_WIDE_INT mask1 = INTVAL (operands[2]); + unsigned HOST_WIDE_INT mask2 = mask1; + int i; + + /* For each byte that isn't all zeros, make it all ones. */ + for (i = 0; i < 64; i += 8) + if ((mask1 & ((HOST_WIDE_INT) 0xff << i)) != 0) + mask1 |= (HOST_WIDE_INT) 0xff << i; + + /* Now turn on any bits we've just turned off. */ + mask2 |= ~ mask1; + + operands[3] = GEN_INT (mask1); + operands[4] = GEN_INT (mask2); +}) + +(define_expand "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" +{ + if (! TARGET_BWX) + operands[1] = force_reg (QImode, operands[1]); +}) + +(define_insn "*zero_extendqihi2_bwx" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (zero_extend:HI (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_extendqihi2_nobwx" + [(set (match_operand:HI 0 "register_operand" "=r") + (zero_extend:HI (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 "nonimmediate_operand" "")))] + "" +{ + if (! TARGET_BWX) + operands[1] = force_reg (QImode, operands[1]); +}) + +(define_insn "*zero_extendqisi2_bwx" + [(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_nobwx" + [(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_extendqidi2" + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" +{ + if (! TARGET_BWX) + operands[1] = force_reg (QImode, operands[1]); +}) + +(define_insn "*zero_extendqidi2_bwx" + [(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 "*zero_extendqidi2_nobwx" + [(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_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" +{ + if (! TARGET_BWX) + operands[1] = force_reg (HImode, operands[1]); +}) + +(define_insn "*zero_extendhisi2_bwx" + [(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_nobwx" + [(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" "shift")]) + +(define_expand "zero_extendhidi2" + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" +{ + if (! TARGET_BWX) + operands[1] = force_reg (HImode, operands[1]); +}) + +(define_insn "*zero_extendhidi2_bwx" + [(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_nobwx" + [(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" "shift")]) + +(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" "shift")]) + +(define_insn "*andnotsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (not:SI (match_operand:SI 1 "reg_or_8bit_operand" "rI")) + (match_operand:SI 2 "reg_or_0_operand" "rJ")))] + "" + "bic %r2,%1,%0" + [(set_attr "type" "ilog")]) + +(define_insn "andnotdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (not:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI")) + (match_operand:DI 2 "reg_or_0_operand" "rJ")))] + "" + "bic %r2,%1,%0" + [(set_attr "type" "ilog")]) + +(define_insn "*iorsi_internal" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (ior:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ") + (match_operand:SI 2 "or_operand" "rI,N")))] + "" + "@ + bis %r1,%2,%0 + ornot %r1,%N2,%0" + [(set_attr "type" "ilog")]) + +(define_insn "iordi3" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (ior:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ,rJ") + (match_operand:DI 2 "or_operand" "rI,N")))] + "" + "@ + bis %r1,%2,%0 + ornot %r1,%N2,%0" + [(set_attr "type" "ilog")]) + +(define_insn "*one_cmplsi_internal" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "reg_or_8bit_operand" "rI")))] + "" + "ornot $31,%1,%0" + [(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" "ilog")]) + +(define_insn "*iornotsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (ior:SI (not:SI (match_operand:SI 1 "reg_or_8bit_operand" "rI")) + (match_operand:SI 2 "reg_or_0_operand" "rJ")))] + "" + "ornot %r2,%1,%0" + [(set_attr "type" "ilog")]) + +(define_insn "*iornotdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (ior:DI (not:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI")) + (match_operand:DI 2 "reg_or_0_operand" "rJ")))] + "" + "ornot %r2,%1,%0" + [(set_attr "type" "ilog")]) + +(define_insn "*xorsi_internal" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (xor:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ,rJ") + (match_operand:SI 2 "or_operand" "rI,N")))] + "" + "@ + xor %r1,%2,%0 + eqv %r1,%N2,%0" + [(set_attr "type" "ilog")]) + +(define_insn "xordi3" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (xor:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ,rJ") + (match_operand:DI 2 "or_operand" "rI,N")))] + "" + "@ + xor %r1,%2,%0 + eqv %r1,%N2,%0" + [(set_attr "type" "ilog")]) + +(define_insn "*xornotsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (xor:SI (match_operand:SI 1 "register_operand" "%rJ") + (match_operand:SI 2 "register_operand" "rI"))))] + "" + "eqv %r1,%2,%0" + [(set_attr "type" "ilog")]) + +(define_insn "*xornotdi3" + [(set (match_operand:DI 0 "register_operand" "=r") + (not:DI (xor:DI (match_operand:DI 1 "register_operand" "%rJ") + (match_operand:DI 2 "register_operand" "rI"))))] + "" + "eqv %r1,%2,%0" + [(set_attr "type" "ilog")]) + +;; Handle FFS and related insns iff we support CIX. + +(define_expand "ffsdi2" + [(set (match_dup 2) + (ctz:DI (match_operand:DI 1 "register_operand" ""))) + (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 "clzdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (clz:DI (match_operand:DI 1 "register_operand" "r")))] + "TARGET_CIX" + "ctlz %1,%0" + [(set_attr "type" "mvi")]) + +(define_insn "ctzdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (ctz:DI (match_operand:DI 1 "register_operand" "r")))] + "TARGET_CIX" + "cttz %1,%0" + [(set_attr "type" "mvi")]) + +(define_insn "popcountdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (popcount:DI (match_operand:DI 1 "register_operand" "r")))] + "TARGET_CIX" + "ctpop %1,%0" + [(set_attr "type" "mvi")]) + +(define_expand "bswapsi2" + [(set (match_operand:SI 0 "register_operand" "") + (bswap:SI (match_operand:SI 1 "register_operand" "")))] + "!optimize_size" +{ + rtx t0, t1; + + t0 = gen_reg_rtx (DImode); + t1 = gen_reg_rtx (DImode); + + emit_insn (gen_insxh (t0, gen_lowpart (DImode, operands[1]), + GEN_INT (32), GEN_INT (WORDS_BIG_ENDIAN ? 0 : 7))); + emit_insn (gen_inswl_const (t1, gen_lowpart (HImode, operands[1]), + GEN_INT (24))); + emit_insn (gen_iordi3 (t1, t0, t1)); + emit_insn (gen_lshrdi3 (t0, t1, GEN_INT (16))); + emit_insn (gen_anddi3 (t1, t1, alpha_expand_zap_mask (0x5))); + emit_insn (gen_anddi3 (t0, t0, alpha_expand_zap_mask (0xa))); + emit_insn (gen_addsi3 (operands[0], gen_lowpart (SImode, t0), + gen_lowpart (SImode, t1))); + DONE; +}) + +(define_expand "bswapdi2" + [(set (match_operand:DI 0 "register_operand" "") + (bswap:DI (match_operand:DI 1 "register_operand" "")))] + "!optimize_size" +{ + rtx t0, t1; + + t0 = gen_reg_rtx (DImode); + t1 = gen_reg_rtx (DImode); + + /* This method of shifting and masking is not specific to Alpha, but + is only profitable on Alpha because of our handy byte zap insn. */ + + emit_insn (gen_lshrdi3 (t0, operands[1], GEN_INT (32))); + emit_insn (gen_ashldi3 (t1, operands[1], GEN_INT (32))); + emit_insn (gen_iordi3 (t1, t0, t1)); + + emit_insn (gen_lshrdi3 (t0, t1, GEN_INT (16))); + emit_insn (gen_ashldi3 (t1, t1, GEN_INT (16))); + emit_insn (gen_anddi3 (t0, t0, alpha_expand_zap_mask (0xcc))); + emit_insn (gen_anddi3 (t1, t1, alpha_expand_zap_mask (0x33))); + emit_insn (gen_iordi3 (t1, t0, t1)); + + emit_insn (gen_lshrdi3 (t0, t1, GEN_INT (8))); + emit_insn (gen_ashldi3 (t1, t1, GEN_INT (8))); + emit_insn (gen_anddi3 (t0, t0, alpha_expand_zap_mask (0xaa))); + emit_insn (gen_anddi3 (t1, t1, alpha_expand_zap_mask (0x55))); + emit_insn (gen_iordi3 (operands[0], t0, t1)); + DONE; +}) + +;; 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,rS")))] + "" +{ + switch (which_alternative) + { + case 0: + if (operands[2] == const1_rtx) + return "addq %r1,%r1,%0"; + else + return "s%P2addq %r1,0,%0"; + case 1: + return "sll %r1,%2,%0"; + default: + gcc_unreachable (); + } +} + [(set_attr "type" "iadd,shift")]) + +(define_insn "*ashldi_se" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (subreg:SI (ashift:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (match_operand:DI 2 "const_int_operand" "P")) + 0)))] + "INTVAL (operands[2]) >= 1 && INTVAL (operands[2]) <= 3" +{ + if (operands[2] == const1_rtx) + return "addl %r1,%r1,%0"; + else + return "s%P2addl %r1,0,%0"; +} + [(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" "rS")))] + "" + "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" "rS")))] + "" + "sra %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_expand "extendqihi2" + [(set (match_dup 2) + (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)))] + "" +{ + 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 "some_operand" "") + (const_int 56))) + (set (match_operand:SI 0 "register_operand" "") + (ashiftrt:DI (match_dup 2) + (const_int 56)))] + "" +{ + 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 "some_operand" "") + (const_int 56))) + (set (match_operand:DI 0 "register_operand" "") + (ashiftrt:DI (match_dup 2) + (const_int 56)))] + "" +{ + 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], XEXP (operands[1], 0)); + 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 "some_operand" "") + (const_int 48))) + (set (match_operand:SI 0 "register_operand" "") + (ashiftrt:DI (match_dup 2) + (const_int 48)))] + "" +{ + 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 "some_operand" "") + (const_int 48))) + (set (match_operand:DI 0 "register_operand" "") + (ashiftrt:DI (match_dup 2) + (const_int 48)))] + "" +{ + 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], XEXP (operands[1], 0)); + + 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, operand 0 is the result. +(define_expand "unaligned_extendqidi" + [(use (match_operand:QI 0 "register_operand" "")) + (use (match_operand:DI 1 "address_operand" ""))] + "" +{ + operands[0] = gen_lowpart (DImode, operands[0]); + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_extendqidi_be (operands[0], operands[1])); + else + emit_insn (gen_unaligned_extendqidi_le (operands[0], operands[1])); + DONE; +}) + +(define_expand "unaligned_extendqidi_le" + [(set (match_dup 3) + (mem:DI (and:DI (match_operand:DI 1 "" "") (const_int -8)))) + (set (match_dup 4) + (ashift:DI (match_dup 3) + (minus:DI (const_int 64) + (ashift:DI + (and:DI (match_dup 2) (const_int 7)) + (const_int 3))))) + (set (match_operand:DI 0 "register_operand" "") + (ashiftrt:DI (match_dup 4) (const_int 56)))] + "! WORDS_BIG_ENDIAN" +{ + operands[2] = get_unaligned_offset (operands[1], 1); + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); +}) + +(define_expand "unaligned_extendqidi_be" + [(set (match_dup 3) + (mem:DI (and:DI (match_operand:DI 1 "" "") (const_int -8)))) + (set (match_dup 4) + (ashift:DI (match_dup 3) + (ashift:DI + (and:DI + (plus:DI (match_dup 2) (const_int 1)) + (const_int 7)) + (const_int 3)))) + (set (match_operand:DI 0 "register_operand" "") + (ashiftrt:DI (match_dup 4) (const_int 56)))] + "WORDS_BIG_ENDIAN" +{ + operands[2] = get_unaligned_offset (operands[1], -1); + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); +}) + +(define_expand "unaligned_extendhidi" + [(use (match_operand:QI 0 "register_operand" "")) + (use (match_operand:DI 1 "address_operand" ""))] + "" +{ + operands[0] = gen_lowpart (DImode, operands[0]); + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_extendhidi_be (operands[0], operands[1])); + else + emit_insn (gen_unaligned_extendhidi_le (operands[0], operands[1])); + DONE; +}) + +(define_expand "unaligned_extendhidi_le" + [(set (match_dup 3) + (mem:DI (and:DI (match_operand:DI 1 "" "") (const_int -8)))) + (set (match_dup 4) + (ashift:DI (match_dup 3) + (minus:DI (const_int 64) + (ashift:DI + (and:DI (match_dup 2) (const_int 7)) + (const_int 3))))) + (set (match_operand:DI 0 "register_operand" "") + (ashiftrt:DI (match_dup 4) (const_int 48)))] + "! WORDS_BIG_ENDIAN" +{ + operands[2] = get_unaligned_offset (operands[1], 2); + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); +}) + +(define_expand "unaligned_extendhidi_be" + [(set (match_dup 3) + (mem:DI (and:DI (match_operand:DI 1 "" "") (const_int -8)))) + (set (match_dup 4) + (ashift:DI (match_dup 3) + (ashift:DI + (and:DI + (plus:DI (match_dup 2) (const_int 1)) + (const_int 7)) + (const_int 3)))) + (set (match_operand:DI 0 "register_operand" "") + (ashiftrt:DI (match_dup 4) (const_int 48)))] + "WORDS_BIG_ENDIAN" +{ + operands[2] = get_unaligned_offset (operands[1], -1); + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); +}) + +(define_insn "*extxl_const" + [(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" + [(set_attr "type" "shift")]) + +(define_insn "extxl_le" + [(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))))] + "! WORDS_BIG_ENDIAN" + "ext%M2l %r1,%3,%0" + [(set_attr "type" "shift")]) + +(define_insn "extxl_be" + [(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") + (minus:DI + (const_int 56) + (ashift:DI + (match_operand:DI 3 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" + "ext%M2l %r1,%3,%0" + [(set_attr "type" "shift")]) + +;; Combine has some strange notion of preserving existing undefined behavior +;; in shifts larger than a word size. So capture these patterns that it +;; should have turned into zero_extracts. + +(define_insn "*extxl_1_le" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3))) + (match_operand:DI 3 "mode_mask_operand" "n")))] + "! WORDS_BIG_ENDIAN" + "ext%U3l %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "*extxl_1_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (lshiftrt:DI + (match_operand:DI 1 "reg_or_0_operand" "rJ") + (minus:DI (const_int 56) + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))) + (match_operand:DI 3 "mode_mask_operand" "n")))] + "WORDS_BIG_ENDIAN" + "ext%U3l %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "*extql_2_le" + [(set (match_operand:DI 0 "register_operand" "=r") + (lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3))))] + "! WORDS_BIG_ENDIAN" + "extql %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "*extql_2_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (lshiftrt:DI + (match_operand:DI 1 "reg_or_0_operand" "rJ") + (minus:DI (const_int 56) + (ashift:DI + (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" + "extql %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extqh_le" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI + (match_operand:DI 1 "reg_or_0_operand" "rJ") + (minus:DI (const_int 64) + (ashift:DI + (and:DI + (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 7)) + (const_int 3)))))] + "! WORDS_BIG_ENDIAN" + "extqh %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extqh_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI + (match_operand:DI 1 "reg_or_0_operand" "rJ") + (ashift:DI + (and:DI + (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 1)) + (const_int 7)) + (const_int 3))))] + "WORDS_BIG_ENDIAN" + "extqh %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extlh_le" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI + (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (const_int 2147483647)) + (minus:DI (const_int 64) + (ashift:DI + (and:DI + (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 7)) + (const_int 3)))))] + "! WORDS_BIG_ENDIAN" + "extlh %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extlh_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI + (ashift:DI + (match_operand:DI 1 "reg_or_0_operand" "rJ") + (ashift:DI + (and:DI + (plus:DI + (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 1)) + (const_int 7)) + (const_int 3))) + (const_int 2147483647)))] + "WORDS_BIG_ENDIAN" + "extlh %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extwh_le" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI + (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (const_int 65535)) + (minus:DI (const_int 64) + (ashift:DI + (and:DI + (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 7)) + (const_int 3)))))] + "! WORDS_BIG_ENDIAN" + "extwh %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "extwh_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI + (ashift:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (ashift:DI + (and:DI + (plus:DI + (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 1)) + (const_int 7)) + (const_int 3))) + (const_int 65535)))] + "WORDS_BIG_ENDIAN" + "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_insn "*insbl_const" + [(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" + [(set_attr "type" "shift")]) + +(define_insn "inswl_const" + [(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" + [(set_attr "type" "shift")]) + +(define_insn "*insll_const" + [(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" + [(set_attr "type" "shift")]) + +(define_insn "insbl_le" + [(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))))] + "! WORDS_BIG_ENDIAN" + "insbl %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "insbl_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r")) + (minus:DI (const_int 56) + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" + "insbl %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "inswl_le" + [(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))))] + "! WORDS_BIG_ENDIAN" + "inswl %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "inswl_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r")) + (minus:DI (const_int 56) + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" + "inswl %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "insll_le" + [(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))))] + "! WORDS_BIG_ENDIAN" + "insll %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "insll_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) + (minus:DI (const_int 56) + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" + "insll %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "insql_le" + [(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))))] + "! WORDS_BIG_ENDIAN" + "insql %1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "insql_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (match_operand:DI 1 "register_operand" "r") + (minus:DI (const_int 56) + (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI") + (const_int 3)))))] + "WORDS_BIG_ENDIAN" + "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 "*insxl" + [(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 + && CONST_INT_P (operands[3]) + && (((unsigned HOST_WIDE_INT) 0xff << INTVAL (operands[2]) + == (unsigned HOST_WIDE_INT) INTVAL (operands[3])) + || ((unsigned HOST_WIDE_INT) 0xffff << INTVAL (operands[2]) + == (unsigned HOST_WIDE_INT) INTVAL (operands[3])) + || ((unsigned HOST_WIDE_INT) 0xffffffff << INTVAL (operands[2]) + == (unsigned HOST_WIDE_INT) INTVAL (operands[3])))" +{ +#if HOST_BITS_PER_WIDE_INT == 64 + if ((unsigned HOST_WIDE_INT) 0xff << INTVAL (operands[2]) + == (unsigned HOST_WIDE_INT) INTVAL (operands[3])) + return "insbl %1,%s2,%0"; + if ((unsigned HOST_WIDE_INT) 0xffff << INTVAL (operands[2]) + == (unsigned HOST_WIDE_INT) INTVAL (operands[3])) + return "inswl %1,%s2,%0"; + if ((unsigned HOST_WIDE_INT) 0xffffffff << INTVAL (operands[2]) + == (unsigned HOST_WIDE_INT) INTVAL (operands[3])) + return "insll %1,%s2,%0"; +#endif + gcc_unreachable (); +} + [(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 "insxh" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mode_width_operand" "n") + (match_operand:DI 3 "reg_or_8bit_operand" "rI")] + UNSPEC_INSXH))] + "" + "ins%M2h %1,%3,%0" + [(set_attr "type" "shift")]) + +(define_insn "mskxl_le" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (not:DI (ashift:DI + (match_operand:DI 2 "mode_mask_operand" "n") + (ashift:DI + (match_operand:DI 3 "reg_or_8bit_operand" "rI") + (const_int 3)))) + (match_operand:DI 1 "reg_or_0_operand" "rJ")))] + "! WORDS_BIG_ENDIAN" + "msk%U2l %r1,%3,%0" + [(set_attr "type" "shift")]) + +(define_insn "mskxl_be" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (not:DI (ashift:DI + (match_operand:DI 2 "mode_mask_operand" "n") + (minus:DI (const_int 56) + (ashift:DI + (match_operand:DI 3 "reg_or_8bit_operand" "rI") + (const_int 3))))) + (match_operand:DI 1 "reg_or_0_operand" "rJ")))] + "WORDS_BIG_ENDIAN" + "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. +;; +;; Again, we do for block moves and we use unspec again. + +(define_insn "mskxh" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "mode_width_operand" "n") + (match_operand:DI 3 "reg_or_8bit_operand" "rI")] + UNSPEC_MSKXH))] + "" + "msk%M2h %1,%3,%0" + [(set_attr "type" "shift")]) + +;; Prefer AND + NE over LSHIFTRT + AND. + +(define_insn_and_split "*ze_and_ne" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (const_int 1) + (match_operand 2 "const_int_operand" "I")))] + "(unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 8" + "#" + "(unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 8" + [(set (match_dup 0) + (and:DI (match_dup 1) (match_dup 3))) + (set (match_dup 0) + (ne:DI (match_dup 0) (const_int 0)))] + "operands[3] = GEN_INT (1 << INTVAL (operands[2]));") + +;; Floating-point operations. All the double-precision insns can extend +;; from single, so indicate that. The exception are the ones that simply +;; play with the sign bits; it's not clear what to do there. + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (abs:SF (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "cpys $f31,%R1,%0" + [(set_attr "type" "fcpys")]) + +(define_insn "*nabssf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (abs:SF (match_operand:SF 1 "reg_or_0_operand" "fG"))))] + "TARGET_FP" + "cpysn $f31,%R1,%0" + [(set_attr "type" "fadd")]) + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (abs:DF (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "cpys $f31,%R1,%0" + [(set_attr "type" "fcpys")]) + +(define_insn "*nabsdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (abs:DF (match_operand:DF 1 "reg_or_0_operand" "fG"))))] + "TARGET_FP" + "cpysn $f31,%R1,%0" + [(set_attr "type" "fadd")]) + +(define_expand "abstf2" + [(parallel [(set (match_operand:TF 0 "register_operand" "") + (abs:TF (match_operand:TF 1 "reg_or_0_operand" ""))) + (use (match_dup 2))])] + "TARGET_HAS_XFLOATING_LIBS" +{ +#if HOST_BITS_PER_WIDE_INT >= 64 + operands[2] = force_reg (DImode, GEN_INT ((HOST_WIDE_INT) 1 << 63)); +#else + operands[2] = force_reg (DImode, immed_double_const (0, 0x80000000, DImode)); +#endif +}) + +(define_insn_and_split "*abstf_internal" + [(set (match_operand:TF 0 "register_operand" "=r") + (abs:TF (match_operand:TF 1 "reg_or_0_operand" "rG"))) + (use (match_operand:DI 2 "register_operand" "r"))] + "TARGET_HAS_XFLOATING_LIBS" + "#" + "&& reload_completed" + [(const_int 0)] + "alpha_split_tfmode_frobsign (operands, gen_andnotdi3); DONE;") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "cpysn %R1,%R1,%0" + [(set_attr "type" "fadd")]) + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "cpysn %R1,%R1,%0" + [(set_attr "type" "fadd")]) + +(define_expand "negtf2" + [(parallel [(set (match_operand:TF 0 "register_operand" "") + (neg:TF (match_operand:TF 1 "reg_or_0_operand" ""))) + (use (match_dup 2))])] + "TARGET_HAS_XFLOATING_LIBS" +{ +#if HOST_BITS_PER_WIDE_INT >= 64 + operands[2] = force_reg (DImode, GEN_INT ((HOST_WIDE_INT) 1 << 63)); +#else + operands[2] = force_reg (DImode, immed_double_const (0, 0x80000000, DImode)); +#endif +}) + +(define_insn_and_split "*negtf_internal" + [(set (match_operand:TF 0 "register_operand" "=r") + (neg:TF (match_operand:TF 1 "reg_or_0_operand" "rG"))) + (use (match_operand:DI 2 "register_operand" "r"))] + "TARGET_HAS_XFLOATING_LIBS" + "#" + "&& reload_completed" + [(const_int 0)] + "alpha_split_tfmode_frobsign (operands, gen_xordi3); DONE;") + +(define_insn "copysignsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (unspec:SF [(match_operand:SF 1 "reg_or_0_operand" "fG") + (match_operand:SF 2 "reg_or_0_operand" "fG")] + UNSPEC_COPYSIGN))] + "TARGET_FP" + "cpys %R2,%R1,%0" + [(set_attr "type" "fadd")]) + +(define_insn "*ncopysignsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (neg:SF (unspec:SF [(match_operand:SF 1 "reg_or_0_operand" "fG") + (match_operand:SF 2 "reg_or_0_operand" "fG")] + UNSPEC_COPYSIGN)))] + "TARGET_FP" + "cpysn %R2,%R1,%0" + [(set_attr "type" "fadd")]) + +(define_insn "copysigndf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(match_operand:DF 1 "reg_or_0_operand" "fG") + (match_operand:DF 2 "reg_or_0_operand" "fG")] + UNSPEC_COPYSIGN))] + "TARGET_FP" + "cpys %R2,%R1,%0" + [(set_attr "type" "fadd")]) + +(define_insn "*ncopysigndf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (neg:DF (unspec:DF [(match_operand:DF 1 "reg_or_0_operand" "fG") + (match_operand:DF 2 "reg_or_0_operand" "fG")] + UNSPEC_COPYSIGN)))] + "TARGET_FP" + "cpysn %R2,%R1,%0" + [(set_attr "type" "fadd")]) + +(define_insn "*addsf_ieee" + [(set (match_operand:SF 0 "register_operand" "=&f") + (plus:SF (match_operand:SF 1 "reg_or_0_operand" "%fG") + (match_operand:SF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "add%,%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (plus:SF (match_operand:SF 1 "reg_or_0_operand" "%fG") + (match_operand:SF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "add%,%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*adddf_ieee" + [(set (match_operand:DF 0 "register_operand" "=&f") + (plus:DF (match_operand:DF 1 "reg_or_0_operand" "%fG") + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "add%-%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (match_operand:DF 1 "reg_or_0_operand" "%fG") + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "add%-%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*adddf_ext1" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (float_extend:DF + (match_operand:SF 1 "reg_or_0_operand" "fG")) + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "add%-%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*adddf_ext2" + [(set (match_operand:DF 0 "register_operand" "=f") + (plus:DF (float_extend:DF + (match_operand:SF 1 "reg_or_0_operand" "%fG")) + (float_extend:DF + (match_operand:SF 2 "reg_or_0_operand" "fG"))))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "add%-%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_expand "addtf3" + [(use (match_operand 0 "register_operand" "")) + (use (match_operand 1 "general_operand" "")) + (use (match_operand 2 "general_operand" ""))] + "TARGET_HAS_XFLOATING_LIBS" + "alpha_emit_xfloating_arith (PLUS, operands); DONE;") + +;; 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. +;; +;; Note that we (attempt to) only consider this optimization when the +;; ultimate destination is memory. If we will be doing further integer +;; processing, it is cheaper to do the truncation in the int regs. + +(define_insn "*cvtql" + [(set (match_operand:SF 0 "register_operand" "=f") + (unspec:SF [(match_operand:DI 1 "reg_or_0_operand" "fG")] + UNSPEC_CVTQL))] + "TARGET_FP" + "cvtql%/ %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "trap_suffix" "v_sv")]) + +(define_insn_and_split "*fix_truncdfsi_ieee" + [(set (match_operand:SI 0 "memory_operand" "=m") + (subreg:SI + (match_operator:DI 4 "fix_operator" + [(match_operand:DF 1 "reg_or_0_operand" "fG")]) 0)) + (clobber (match_scratch:DI 2 "=&f")) + (clobber (match_scratch:SF 3 "=&f"))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "#" + "&& reload_completed" + [(set (match_dup 2) (match_op_dup 4 [(match_dup 1)])) + (set (match_dup 3) (unspec:SF [(match_dup 2)] UNSPEC_CVTQL)) + (set (match_dup 5) (match_dup 3))] +{ + operands[5] = adjust_address (operands[0], SFmode, 0); +} + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn_and_split "*fix_truncdfsi_internal" + [(set (match_operand:SI 0 "memory_operand" "=m") + (subreg:SI + (match_operator:DI 3 "fix_operator" + [(match_operand:DF 1 "reg_or_0_operand" "fG")]) 0)) + (clobber (match_scratch:DI 2 "=f"))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "#" + "&& reload_completed" + [(set (match_dup 2) (match_op_dup 3 [(match_dup 1)])) + (set (match_dup 4) (unspec:SF [(match_dup 2)] UNSPEC_CVTQL)) + (set (match_dup 5) (match_dup 4))] +{ + operands[4] = gen_rtx_REG (SFmode, REGNO (operands[2])); + operands[5] = adjust_address (operands[0], SFmode, 0); +} + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "*fix_truncdfdi_ieee" + [(set (match_operand:DI 0 "reg_no_subreg_operand" "=&f") + (match_operator:DI 2 "fix_operator" + [(match_operand:DF 1 "reg_or_0_operand" "fG")]))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "cvt%-q%/ %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "c") + (set_attr "trap_suffix" "v_sv_svi")]) + +(define_insn "*fix_truncdfdi2" + [(set (match_operand:DI 0 "reg_no_subreg_operand" "=f") + (match_operator:DI 2 "fix_operator" + [(match_operand:DF 1 "reg_or_0_operand" "fG")]))] + "TARGET_FP" + "cvt%-q%/ %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "c") + (set_attr "trap_suffix" "v_sv_svi")]) + +(define_expand "fix_truncdfdi2" + [(set (match_operand:DI 0 "reg_no_subreg_operand" "") + (fix:DI (match_operand:DF 1 "reg_or_0_operand" "")))] + "TARGET_FP" + "") + +(define_expand "fixuns_truncdfdi2" + [(set (match_operand:DI 0 "reg_no_subreg_operand" "") + (unsigned_fix:DI (match_operand:DF 1 "reg_or_0_operand" "")))] + "TARGET_FP" + "") + +;; Likewise between SFmode and SImode. + +(define_insn_and_split "*fix_truncsfsi_ieee" + [(set (match_operand:SI 0 "memory_operand" "=m") + (subreg:SI + (match_operator:DI 4 "fix_operator" + [(float_extend:DF + (match_operand:SF 1 "reg_or_0_operand" "fG"))]) 0)) + (clobber (match_scratch:DI 2 "=&f")) + (clobber (match_scratch:SF 3 "=&f"))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "#" + "&& reload_completed" + [(set (match_dup 2) (match_op_dup 4 [(float_extend:DF (match_dup 1))])) + (set (match_dup 3) (unspec:SF [(match_dup 2)] UNSPEC_CVTQL)) + (set (match_dup 5) (match_dup 3))] +{ + operands[5] = adjust_address (operands[0], SFmode, 0); +} + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn_and_split "*fix_truncsfsi_internal" + [(set (match_operand:SI 0 "memory_operand" "=m") + (subreg:SI + (match_operator:DI 3 "fix_operator" + [(float_extend:DF + (match_operand:SF 1 "reg_or_0_operand" "fG"))]) 0)) + (clobber (match_scratch:DI 2 "=f"))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "#" + "&& reload_completed" + [(set (match_dup 2) (match_op_dup 3 [(float_extend:DF (match_dup 1))])) + (set (match_dup 4) (unspec:SF [(match_dup 2)] UNSPEC_CVTQL)) + (set (match_dup 5) (match_dup 4))] +{ + operands[4] = gen_rtx_REG (SFmode, REGNO (operands[2])); + operands[5] = adjust_address (operands[0], SFmode, 0); +} + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "*fix_truncsfdi_ieee" + [(set (match_operand:DI 0 "reg_no_subreg_operand" "=&f") + (match_operator:DI 2 "fix_operator" + [(float_extend:DF (match_operand:SF 1 "reg_or_0_operand" "fG"))]))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "cvt%-q%/ %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "c") + (set_attr "trap_suffix" "v_sv_svi")]) + +(define_insn "*fix_truncsfdi2" + [(set (match_operand:DI 0 "reg_no_subreg_operand" "=f") + (match_operator:DI 2 "fix_operator" + [(float_extend:DF (match_operand:SF 1 "reg_or_0_operand" "fG"))]))] + "TARGET_FP" + "cvt%-q%/ %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "c") + (set_attr "trap_suffix" "v_sv_svi")]) + +(define_expand "fix_truncsfdi2" + [(set (match_operand:DI 0 "reg_no_subreg_operand" "") + (fix:DI (float_extend:DF (match_operand:SF 1 "reg_or_0_operand" ""))))] + "TARGET_FP" + "") + +(define_expand "fixuns_truncsfdi2" + [(set (match_operand:DI 0 "reg_no_subreg_operand" "") + (unsigned_fix:DI + (float_extend:DF (match_operand:SF 1 "reg_or_0_operand" ""))))] + "TARGET_FP" + "") + +(define_expand "fix_trunctfdi2" + [(use (match_operand:DI 0 "register_operand" "")) + (use (match_operand:TF 1 "general_operand" ""))] + "TARGET_HAS_XFLOATING_LIBS" + "alpha_emit_xfloating_cvt (FIX, operands); DONE;") + +(define_expand "fixuns_trunctfdi2" + [(use (match_operand:DI 0 "register_operand" "")) + (use (match_operand:TF 1 "general_operand" ""))] + "TARGET_HAS_XFLOATING_LIBS" + "alpha_emit_xfloating_cvt (UNSIGNED_FIX, operands); DONE;") + +(define_insn "*floatdisf_ieee" + [(set (match_operand:SF 0 "register_operand" "=&f") + (float:SF (match_operand:DI 1 "reg_no_subreg_operand" "f")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "cvtq%,%/ %1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "sui")]) + +(define_insn "floatdisf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:DI 1 "reg_no_subreg_operand" "f")))] + "TARGET_FP" + "cvtq%,%/ %1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "sui")]) + +(define_insn_and_split "*floatsisf2_ieee" + [(set (match_operand:SF 0 "register_operand" "=&f") + (float:SF (match_operand:SI 1 "memory_operand" "m"))) + (clobber (match_scratch:DI 2 "=&f")) + (clobber (match_scratch:SF 3 "=&f"))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "#" + "&& reload_completed" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 2) (unspec:DI [(match_dup 3)] UNSPEC_CVTLQ)) + (set (match_dup 0) (float:SF (match_dup 2)))] +{ + operands[1] = adjust_address (operands[1], SFmode, 0); +}) + +(define_insn_and_split "*floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float:SF (match_operand:SI 1 "memory_operand" "m")))] + "TARGET_FP" + "#" + "&& reload_completed" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (unspec:DI [(match_dup 0)] UNSPEC_CVTLQ)) + (set (match_dup 0) (float:SF (match_dup 2)))] +{ + operands[1] = adjust_address (operands[1], SFmode, 0); + operands[2] = gen_rtx_REG (DImode, REGNO (operands[0])); +}) + +(define_insn "*floatdidf_ieee" + [(set (match_operand:DF 0 "register_operand" "=&f") + (float:DF (match_operand:DI 1 "reg_no_subreg_operand" "f")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "cvtq%-%/ %1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "sui")]) + +(define_insn "floatdidf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:DI 1 "reg_no_subreg_operand" "f")))] + "TARGET_FP" + "cvtq%-%/ %1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "sui")]) + +(define_insn_and_split "*floatsidf2_ieee" + [(set (match_operand:DF 0 "register_operand" "=&f") + (float:DF (match_operand:SI 1 "memory_operand" "m"))) + (clobber (match_scratch:DI 2 "=&f")) + (clobber (match_scratch:SF 3 "=&f"))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "#" + "&& reload_completed" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 2) (unspec:DI [(match_dup 3)] UNSPEC_CVTLQ)) + (set (match_dup 0) (float:DF (match_dup 2)))] +{ + operands[1] = adjust_address (operands[1], SFmode, 0); +}) + +(define_insn_and_split "*floatsidf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (float:DF (match_operand:SI 1 "memory_operand" "m")))] + "TARGET_FP" + "#" + "&& reload_completed" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 2) (unspec:DI [(match_dup 3)] UNSPEC_CVTLQ)) + (set (match_dup 0) (float:DF (match_dup 2)))] +{ + operands[1] = adjust_address (operands[1], SFmode, 0); + operands[2] = gen_rtx_REG (DImode, REGNO (operands[0])); + operands[3] = gen_rtx_REG (SFmode, REGNO (operands[0])); +}) + +(define_expand "floatditf2" + [(use (match_operand:TF 0 "register_operand" "")) + (use (match_operand:DI 1 "general_operand" ""))] + "TARGET_HAS_XFLOATING_LIBS" + "alpha_emit_xfloating_cvt (FLOAT, operands); DONE;") + +(define_expand "floatunsdisf2" + [(use (match_operand:SF 0 "register_operand" "")) + (use (match_operand:DI 1 "register_operand" ""))] + "TARGET_FP" + "alpha_emit_floatuns (operands); DONE;") + +(define_expand "floatunsdidf2" + [(use (match_operand:DF 0 "register_operand" "")) + (use (match_operand:DI 1 "register_operand" ""))] + "TARGET_FP" + "alpha_emit_floatuns (operands); DONE;") + +(define_expand "floatunsditf2" + [(use (match_operand:TF 0 "register_operand" "")) + (use (match_operand:DI 1 "general_operand" ""))] + "TARGET_HAS_XFLOATING_LIBS" + "alpha_emit_xfloating_cvt (UNSIGNED_FLOAT, operands); DONE;") + +(define_expand "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "") + (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "")))] + "TARGET_FP" +{ + if (alpha_fptm >= ALPHA_FPTM_SU) + operands[1] = force_reg (SFmode, operands[1]); +}) + +;; The Unicos/Mk assembler doesn't support cvtst, but we've already +;; asserted that alpha_fptm == ALPHA_FPTM_N. + +(define_insn "*extendsfdf2_ieee" + [(set (match_operand:DF 0 "register_operand" "=&f") + (float_extend:DF (match_operand:SF 1 "register_operand" "f")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "cvtsts %1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes")]) + +(define_insn "*extendsfdf2_internal" + [(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_fptm < ALPHA_FPTM_SU" + "@ + cpys %1,%1,%0 + ld%, %0,%1 + st%- %1,%0" + [(set_attr "type" "fcpys,fld,fst")]) + +;; Use register_operand for operand 1 to prevent compress_float_constant +;; from doing something silly. When optimizing we'll put things back +;; together anyway. +(define_expand "extendsftf2" + [(use (match_operand:TF 0 "register_operand" "")) + (use (match_operand:SF 1 "register_operand" ""))] + "TARGET_HAS_XFLOATING_LIBS" +{ + rtx tmp = gen_reg_rtx (DFmode); + emit_insn (gen_extendsfdf2 (tmp, operands[1])); + emit_insn (gen_extenddftf2 (operands[0], tmp)); + DONE; +}) + +(define_expand "extenddftf2" + [(use (match_operand:TF 0 "register_operand" "")) + (use (match_operand:DF 1 "register_operand" ""))] + "TARGET_HAS_XFLOATING_LIBS" + "alpha_emit_xfloating_cvt (FLOAT_EXTEND, operands); DONE;") + +(define_insn "*truncdfsf2_ieee" + [(set (match_operand:SF 0 "register_operand" "=&f") + (float_truncate:SF (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "cvt%-%,%/ %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (float_truncate:SF (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "cvt%-%,%/ %R1,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_expand "trunctfdf2" + [(use (match_operand:DF 0 "register_operand" "")) + (use (match_operand:TF 1 "general_operand" ""))] + "TARGET_HAS_XFLOATING_LIBS" + "alpha_emit_xfloating_cvt (FLOAT_TRUNCATE, operands); DONE;") + +(define_expand "trunctfsf2" + [(use (match_operand:SF 0 "register_operand" "")) + (use (match_operand:TF 1 "general_operand" ""))] + "TARGET_FP && TARGET_HAS_XFLOATING_LIBS" +{ + rtx tmpf, sticky, arg, lo, hi; + + tmpf = gen_reg_rtx (DFmode); + sticky = gen_reg_rtx (DImode); + arg = copy_to_mode_reg (TFmode, operands[1]); + lo = gen_lowpart (DImode, arg); + hi = gen_highpart (DImode, arg); + + /* Convert the low word of the TFmode value into a sticky rounding bit, + then or it into the low bit of the high word. This leaves the sticky + bit at bit 48 of the fraction, which is representable in DFmode, + which prevents rounding error in the final conversion to SFmode. */ + + emit_insn (gen_rtx_SET (VOIDmode, sticky, + gen_rtx_NE (DImode, lo, const0_rtx))); + emit_insn (gen_iordi3 (hi, hi, sticky)); + emit_insn (gen_trunctfdf2 (tmpf, arg)); + emit_insn (gen_truncdfsf2 (operands[0], tmpf)); + DONE; +}) + +(define_insn "*divsf3_ieee" + [(set (match_operand:SF 0 "register_operand" "=&f") + (div:SF (match_operand:SF 1 "reg_or_0_operand" "fG") + (match_operand:SF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "div%,%/ %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "opsize" "si") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (div:SF (match_operand:SF 1 "reg_or_0_operand" "fG") + (match_operand:SF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "div%,%/ %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "opsize" "si") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*divdf3_ieee" + [(set (match_operand:DF 0 "register_operand" "=&f") + (div:DF (match_operand:DF 1 "reg_or_0_operand" "fG") + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "div%-%/ %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (div:DF (match_operand:DF 1 "reg_or_0_operand" "fG") + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "div%-%/ %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*divdf_ext1" + [(set (match_operand:DF 0 "register_operand" "=f") + (div:DF (float_extend:DF (match_operand:SF 1 "reg_or_0_operand" "fG")) + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "div%-%/ %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*divdf_ext2" + [(set (match_operand:DF 0 "register_operand" "=f") + (div:DF (match_operand:DF 1 "reg_or_0_operand" "fG") + (float_extend:DF + (match_operand:SF 2 "reg_or_0_operand" "fG"))))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "div%-%/ %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*divdf_ext3" + [(set (match_operand:DF 0 "register_operand" "=f") + (div:DF (float_extend:DF (match_operand:SF 1 "reg_or_0_operand" "fG")) + (float_extend:DF (match_operand:SF 2 "reg_or_0_operand" "fG"))))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "div%-%/ %R1,%R2,%0" + [(set_attr "type" "fdiv") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_expand "divtf3" + [(use (match_operand 0 "register_operand" "")) + (use (match_operand 1 "general_operand" "")) + (use (match_operand 2 "general_operand" ""))] + "TARGET_HAS_XFLOATING_LIBS" + "alpha_emit_xfloating_arith (DIV, operands); DONE;") + +(define_insn "*mulsf3_ieee" + [(set (match_operand:SF 0 "register_operand" "=&f") + (mult:SF (match_operand:SF 1 "reg_or_0_operand" "%fG") + (match_operand:SF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "mul%,%/ %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (mult:SF (match_operand:SF 1 "reg_or_0_operand" "%fG") + (match_operand:SF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "mul%,%/ %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*muldf3_ieee" + [(set (match_operand:DF 0 "register_operand" "=&f") + (mult:DF (match_operand:DF 1 "reg_or_0_operand" "%fG") + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "mul%-%/ %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (match_operand:DF 1 "reg_or_0_operand" "%fG") + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "mul%-%/ %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*muldf_ext1" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (float_extend:DF + (match_operand:SF 1 "reg_or_0_operand" "fG")) + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "mul%-%/ %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*muldf_ext2" + [(set (match_operand:DF 0 "register_operand" "=f") + (mult:DF (float_extend:DF + (match_operand:SF 1 "reg_or_0_operand" "%fG")) + (float_extend:DF + (match_operand:SF 2 "reg_or_0_operand" "fG"))))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "mul%-%/ %R1,%R2,%0" + [(set_attr "type" "fmul") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_expand "multf3" + [(use (match_operand 0 "register_operand" "")) + (use (match_operand 1 "general_operand" "")) + (use (match_operand 2 "general_operand" ""))] + "TARGET_HAS_XFLOATING_LIBS" + "alpha_emit_xfloating_arith (MULT, operands); DONE;") + +(define_insn "*subsf3_ieee" + [(set (match_operand:SF 0 "register_operand" "=&f") + (minus:SF (match_operand:SF 1 "reg_or_0_operand" "fG") + (match_operand:SF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "sub%,%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (minus:SF (match_operand:SF 1 "reg_or_0_operand" "fG") + (match_operand:SF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "sub%,%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*subdf3_ieee" + [(set (match_operand:DF 0 "register_operand" "=&f") + (minus:DF (match_operand:DF 1 "reg_or_0_operand" "fG") + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "sub%-%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (match_operand:DF 1 "reg_or_0_operand" "fG") + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP" + "sub%-%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*subdf_ext1" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (float_extend:DF + (match_operand:SF 1 "reg_or_0_operand" "fG")) + (match_operand:DF 2 "reg_or_0_operand" "fG")))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "sub%-%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*subdf_ext2" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (match_operand:DF 1 "reg_or_0_operand" "fG") + (float_extend:DF + (match_operand:SF 2 "reg_or_0_operand" "fG"))))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "sub%-%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*subdf_ext3" + [(set (match_operand:DF 0 "register_operand" "=f") + (minus:DF (float_extend:DF + (match_operand:SF 1 "reg_or_0_operand" "fG")) + (float_extend:DF + (match_operand:SF 2 "reg_or_0_operand" "fG"))))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "sub%-%/ %R1,%R2,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_expand "subtf3" + [(use (match_operand 0 "register_operand" "")) + (use (match_operand 1 "general_operand" "")) + (use (match_operand 2 "general_operand" ""))] + "TARGET_HAS_XFLOATING_LIBS" + "alpha_emit_xfloating_arith (MINUS, operands); DONE;") + +(define_insn "*sqrtsf2_ieee" + [(set (match_operand:SF 0 "register_operand" "=&f") + (sqrt:SF (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "TARGET_FP && TARGET_FIX && alpha_fptm >= ALPHA_FPTM_SU" + "sqrt%,%/ %R1,%0" + [(set_attr "type" "fsqrt") + (set_attr "opsize" "si") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "=f") + (sqrt:SF (match_operand:SF 1 "reg_or_0_operand" "fG")))] + "TARGET_FP && TARGET_FIX" + "sqrt%,%/ %R1,%0" + [(set_attr "type" "fsqrt") + (set_attr "opsize" "si") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "*sqrtdf2_ieee" + [(set (match_operand:DF 0 "register_operand" "=&f") + (sqrt:DF (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "TARGET_FP && TARGET_FIX && alpha_fptm >= ALPHA_FPTM_SU" + "sqrt%-%/ %R1,%0" + [(set_attr "type" "fsqrt") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "register_operand" "=f") + (sqrt:DF (match_operand:DF 1 "reg_or_0_operand" "fG")))] + "TARGET_FP && TARGET_FIX" + "sqrt%-%/ %R1,%0" + [(set_attr "type" "fsqrt") + (set_attr "trap" "yes") + (set_attr "round_suffix" "normal") + (set_attr "trap_suffix" "u_su_sui")]) + +;; Next are all the integer comparisons, and conditional moves and branches +;; and some of the related define_expand's and define_split's. + +(define_insn "*setcc_internal" + [(set (match_operand 0 "register_operand" "=r") + (match_operator 1 "alpha_comparison_operator" + [(match_operand:DI 2 "register_operand" "r") + (match_operand:DI 3 "reg_or_8bit_operand" "rI")]))] + "GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_INT + && GET_MODE_SIZE (GET_MODE (operands[0])) <= 8 + && GET_MODE (operands[0]) == GET_MODE (operands[1])" + "cmp%C1 %2,%3,%0" + [(set_attr "type" "icmp")]) + +;; Yes, we can technically support reg_or_8bit_operand in operand 2, +;; but that's non-canonical rtl and allowing that causes inefficiencies +;; from cse on. +(define_insn "*setcc_swapped_internal" + [(set (match_operand 0 "register_operand" "=r") + (match_operator 1 "alpha_swapped_comparison_operator" + [(match_operand:DI 2 "register_operand" "r") + (match_operand:DI 3 "reg_or_0_operand" "rJ")]))] + "GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_INT + && GET_MODE_SIZE (GET_MODE (operands[0])) <= 8 + && GET_MODE (operands[0]) == GET_MODE (operands[1])" + "cmp%c1 %r3,%2,%0" + [(set_attr "type" "icmp")]) + +;; Use match_operator rather than ne directly so that we can match +;; multiple integer modes. +(define_insn "*setne_internal" + [(set (match_operand 0 "register_operand" "=r") + (match_operator 1 "signed_comparison_operator" + [(match_operand:DI 2 "register_operand" "r") + (const_int 0)]))] + "GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_INT + && GET_MODE_SIZE (GET_MODE (operands[0])) <= 8 + && GET_CODE (operands[1]) == NE + && GET_MODE (operands[0]) == GET_MODE (operands[1])" + "cmpult $31,%2,%0" + [(set_attr "type" "icmp")]) + +;; The mode folding trick can't be used with const_int operands, since +;; reload needs to know the proper mode. +;; +;; Use add_operand instead of the more seemingly natural reg_or_8bit_operand +;; in order to create more pairs of constants. As long as we're allowing +;; two constants at the same time, and will have to reload one of them... + +(define_insn "*movqicc_internal" + [(set (match_operand:QI 0 "register_operand" "=r,r,r,r") + (if_then_else:QI + (match_operator 2 "signed_comparison_operator" + [(match_operand:DI 3 "reg_or_0_operand" "rJ,rJ,J,J") + (match_operand:DI 4 "reg_or_0_operand" "J,J,rJ,rJ")]) + (match_operand:QI 1 "add_operand" "rI,0,rI,0") + (match_operand:QI 5 "add_operand" "0,rI,0,rI")))] + "(operands[3] == const0_rtx) ^ (operands[4] == const0_rtx)" + "@ + cmov%C2 %r3,%1,%0 + cmov%D2 %r3,%5,%0 + cmov%c2 %r4,%1,%0 + cmov%d2 %r4,%5,%0" + [(set_attr "type" "icmov")]) + +(define_insn "*movhicc_internal" + [(set (match_operand:HI 0 "register_operand" "=r,r,r,r") + (if_then_else:HI + (match_operator 2 "signed_comparison_operator" + [(match_operand:DI 3 "reg_or_0_operand" "rJ,rJ,J,J") + (match_operand:DI 4 "reg_or_0_operand" "J,J,rJ,rJ")]) + (match_operand:HI 1 "add_operand" "rI,0,rI,0") + (match_operand:HI 5 "add_operand" "0,rI,0,rI")))] + "(operands[3] == const0_rtx) ^ (operands[4] == const0_rtx)" + "@ + cmov%C2 %r3,%1,%0 + cmov%D2 %r3,%5,%0 + cmov%c2 %r4,%1,%0 + cmov%d2 %r4,%5,%0" + [(set_attr "type" "icmov")]) + +(define_insn "*movsicc_internal" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") + (if_then_else:SI + (match_operator 2 "signed_comparison_operator" + [(match_operand:DI 3 "reg_or_0_operand" "rJ,rJ,J,J") + (match_operand:DI 4 "reg_or_0_operand" "J,J,rJ,rJ")]) + (match_operand:SI 1 "add_operand" "rI,0,rI,0") + (match_operand:SI 5 "add_operand" "0,rI,0,rI")))] + "(operands[3] == const0_rtx) ^ (operands[4] == const0_rtx)" + "@ + cmov%C2 %r3,%1,%0 + cmov%D2 %r3,%5,%0 + cmov%c2 %r4,%1,%0 + cmov%d2 %r4,%5,%0" + [(set_attr "type" "icmov")]) + +(define_insn "*movdicc_internal" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r") + (if_then_else:DI + (match_operator 2 "signed_comparison_operator" + [(match_operand:DI 3 "reg_or_0_operand" "rJ,rJ,J,J") + (match_operand:DI 4 "reg_or_0_operand" "J,J,rJ,rJ")]) + (match_operand:DI 1 "add_operand" "rI,0,rI,0") + (match_operand:DI 5 "add_operand" "0,rI,0,rI")))] + "(operands[3] == const0_rtx) ^ (operands[4] == const0_rtx)" + "@ + cmov%C2 %r3,%1,%0 + cmov%D2 %r3,%5,%0 + cmov%c2 %r4,%1,%0 + cmov%d2 %r4,%5,%0" + [(set_attr "type" "icmov")]) + +(define_insn "*movqicc_lbc" + [(set (match_operand:QI 0 "register_operand" "=r,r") + (if_then_else:QI + (eq (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ") + (const_int 1) + (const_int 0)) + (const_int 0)) + (match_operand:QI 1 "reg_or_8bit_operand" "rI,0") + (match_operand:QI 3 "reg_or_8bit_operand" "0,rI")))] + "" + "@ + cmovlbc %r2,%1,%0 + cmovlbs %r2,%3,%0" + [(set_attr "type" "icmov")]) + +(define_insn "*movhicc_lbc" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (if_then_else:HI + (eq (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ") + (const_int 1) + (const_int 0)) + (const_int 0)) + (match_operand:HI 1 "reg_or_8bit_operand" "rI,0") + (match_operand:HI 3 "reg_or_8bit_operand" "0,rI")))] + "" + "@ + cmovlbc %r2,%1,%0 + cmovlbs %r2,%3,%0" + [(set_attr "type" "icmov")]) + +(define_insn "*movsicc_lbc" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (if_then_else:SI + (eq (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ") + (const_int 1) + (const_int 0)) + (const_int 0)) + (match_operand:SI 1 "reg_or_8bit_operand" "rI,0") + (match_operand:SI 3 "reg_or_8bit_operand" "0,rI")))] + "" + "@ + cmovlbc %r2,%1,%0 + cmovlbs %r2,%3,%0" + [(set_attr "type" "icmov")]) + +(define_insn "*movdicc_lbc" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (if_then_else:DI + (eq (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ") + (const_int 1) + (const_int 0)) + (const_int 0)) + (match_operand:DI 1 "reg_or_8bit_operand" "rI,0") + (match_operand:DI 3 "reg_or_8bit_operand" "0,rI")))] + "" + "@ + cmovlbc %r2,%1,%0 + cmovlbs %r2,%3,%0" + [(set_attr "type" "icmov")]) + +(define_insn "*movqicc_lbs" + [(set (match_operand:QI 0 "register_operand" "=r,r") + (if_then_else:QI + (ne (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ") + (const_int 1) + (const_int 0)) + (const_int 0)) + (match_operand:QI 1 "reg_or_8bit_operand" "rI,0") + (match_operand:QI 3 "reg_or_8bit_operand" "0,rI")))] + "" + "@ + cmovlbs %r2,%1,%0 + cmovlbc %r2,%3,%0" + [(set_attr "type" "icmov")]) + +(define_insn "*movhicc_lbs" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (if_then_else:HI + (ne (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ") + (const_int 1) + (const_int 0)) + (const_int 0)) + (match_operand:HI 1 "reg_or_8bit_operand" "rI,0") + (match_operand:HI 3 "reg_or_8bit_operand" "0,rI")))] + "" + "@ + cmovlbs %r2,%1,%0 + cmovlbc %r2,%3,%0" + [(set_attr "type" "icmov")]) + +(define_insn "*movsicc_lbs" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (if_then_else:SI + (ne (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ") + (const_int 1) + (const_int 0)) + (const_int 0)) + (match_operand:SI 1 "reg_or_8bit_operand" "rI,0") + (match_operand:SI 3 "reg_or_8bit_operand" "0,rI")))] + "" + "@ + cmovlbs %r2,%1,%0 + cmovlbc %r2,%3,%0" + [(set_attr "type" "icmov")]) + +(define_insn "*movdicc_lbs" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (if_then_else:DI + (ne (zero_extract:DI (match_operand:DI 2 "reg_or_0_operand" "rJ,rJ") + (const_int 1) + (const_int 0)) + (const_int 0)) + (match_operand:DI 1 "reg_or_8bit_operand" "rI,0") + (match_operand:DI 3 "reg_or_8bit_operand" "0,rI")))] + "" + "@ + cmovlbs %r2,%1,%0 + cmovlbc %r2,%3,%0" + [(set_attr "type" "icmov")]) + +;; For ABS, we have two choices, depending on whether the input and output +;; registers are the same or not. +(define_expand "absdi2" + [(set (match_operand:DI 0 "register_operand" "") + (abs:DI (match_operand:DI 1 "register_operand" "")))] + "" +{ + if (rtx_equal_p (operands[0], operands[1])) + emit_insn (gen_absdi2_same (operands[0], gen_reg_rtx (DImode))); + else + emit_insn (gen_absdi2_diff (operands[0], operands[1])); + DONE; +}) + +(define_expand "absdi2_same" + [(set (match_operand:DI 1 "register_operand" "") + (neg:DI (match_operand:DI 0 "register_operand" ""))) + (set (match_dup 0) + (if_then_else:DI (ge (match_dup 0) (const_int 0)) + (match_dup 0) + (match_dup 1)))] + "" + "") + +(define_expand "absdi2_diff" + [(set (match_operand:DI 0 "register_operand" "") + (neg:DI (match_operand:DI 1 "register_operand" ""))) + (set (match_dup 0) + (if_then_else:DI (lt (match_dup 1) (const_int 0)) + (match_dup 0) + (match_dup 1)))] + "" + "") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (abs:DI (match_dup 0))) + (clobber (match_operand:DI 1 "register_operand" ""))] + "" + [(set (match_dup 1) (neg:DI (match_dup 0))) + (set (match_dup 0) (if_then_else:DI (ge (match_dup 0) (const_int 0)) + (match_dup 0) (match_dup 1)))] + "") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (abs:DI (match_operand:DI 1 "register_operand" "")))] + "! rtx_equal_p (operands[0], operands[1])" + [(set (match_dup 0) (neg:DI (match_dup 1))) + (set (match_dup 0) (if_then_else:DI (lt (match_dup 1) (const_int 0)) + (match_dup 0) (match_dup 1)))] + "") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (neg:DI (abs:DI (match_dup 0)))) + (clobber (match_operand:DI 1 "register_operand" ""))] + "" + [(set (match_dup 1) (neg:DI (match_dup 0))) + (set (match_dup 0) (if_then_else:DI (le (match_dup 0) (const_int 0)) + (match_dup 0) (match_dup 1)))] + "") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (neg:DI (abs:DI (match_operand:DI 1 "register_operand" ""))))] + "! rtx_equal_p (operands[0], operands[1])" + [(set (match_dup 0) (neg:DI (match_dup 1))) + (set (match_dup 0) (if_then_else:DI (gt (match_dup 1) (const_int 0)) + (match_dup 0) (match_dup 1)))] + "") + +(define_insn "sminqi3" + [(set (match_operand:QI 0 "register_operand" "=r") + (smin:QI (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:QI (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:QI (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:QI (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:HI (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:HI (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:HI (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:HI (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" "mvi")]) + +(define_expand "smaxdi3" + [(set (match_dup 3) + (le:DI (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" ""))) + (set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (eq (match_dup 3) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "" + { operands[3] = gen_reg_rtx (DImode); }) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (smax:DI (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" ""))) + (clobber (match_operand:DI 3 "register_operand" ""))] + "operands[2] != const0_rtx" + [(set (match_dup 3) (le:DI (match_dup 1) (match_dup 2))) + (set (match_dup 0) (if_then_else:DI (eq (match_dup 3) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "") + +(define_insn "*smax_const0" + [(set (match_operand:DI 0 "register_operand" "=r") + (smax:DI (match_operand:DI 1 "register_operand" "0") + (const_int 0)))] + "" + "cmovlt %0,0,%0" + [(set_attr "type" "icmov")]) + +(define_expand "smindi3" + [(set (match_dup 3) + (lt:DI (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" ""))) + (set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (ne (match_dup 3) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "" + { operands[3] = gen_reg_rtx (DImode); }) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (smin:DI (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" ""))) + (clobber (match_operand:DI 3 "register_operand" ""))] + "operands[2] != const0_rtx" + [(set (match_dup 3) (lt:DI (match_dup 1) (match_dup 2))) + (set (match_dup 0) (if_then_else:DI (ne (match_dup 3) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "") + +(define_insn "*smin_const0" + [(set (match_operand:DI 0 "register_operand" "=r") + (smin:DI (match_operand:DI 1 "register_operand" "0") + (const_int 0)))] + "" + "cmovgt %0,0,%0" + [(set_attr "type" "icmov")]) + +(define_expand "umaxdi3" + [(set (match_dup 3) + (leu:DI (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" ""))) + (set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (eq (match_dup 3) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "" + "operands[3] = gen_reg_rtx (DImode);") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (umax:DI (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" ""))) + (clobber (match_operand:DI 3 "register_operand" ""))] + "operands[2] != const0_rtx" + [(set (match_dup 3) (leu:DI (match_dup 1) (match_dup 2))) + (set (match_dup 0) (if_then_else:DI (eq (match_dup 3) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "") + +(define_expand "umindi3" + [(set (match_dup 3) + (ltu:DI (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" ""))) + (set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (ne (match_dup 3) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "" + "operands[3] = gen_reg_rtx (DImode);") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (umin:DI (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" ""))) + (clobber (match_operand:DI 3 "register_operand" ""))] + "operands[2] != const0_rtx" + [(set (match_dup 3) (ltu:DI (match_dup 1) (match_dup 2))) + (set (match_dup 0) (if_then_else:DI (ne (match_dup 3) (const_int 0)) + (match_dup 1) (match_dup 2)))] + "") + +(define_insn "*bcc_normal" + [(set (pc) + (if_then_else + (match_operator 1 "signed_comparison_operator" + [(match_operand:DI 2 "reg_or_0_operand" "rJ") + (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "b%C1 %r2,%0" + [(set_attr "type" "ibr")]) + +(define_insn "*bcc_reverse" + [(set (pc) + (if_then_else + (match_operator 1 "signed_comparison_operator" + [(match_operand:DI 2 "register_operand" "r") + (const_int 0)]) + + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "b%c1 %2,%0" + [(set_attr "type" "ibr")]) + +(define_insn "*blbs_normal" + [(set (pc) + (if_then_else + (ne (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (const_int 1) + (const_int 0)) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "blbs %r1,%0" + [(set_attr "type" "ibr")]) + +(define_insn "*blbc_normal" + [(set (pc) + (if_then_else + (eq (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ") + (const_int 1) + (const_int 0)) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "blbc %r1,%0" + [(set_attr "type" "ibr")]) + +(define_split + [(parallel + [(set (pc) + (if_then_else + (match_operator 1 "comparison_operator" + [(zero_extract:DI (match_operand:DI 2 "register_operand" "") + (const_int 1) + (match_operand:DI 3 "const_int_operand" "")) + (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc))) + (clobber (match_operand:DI 4 "register_operand" ""))])] + "INTVAL (operands[3]) != 0" + [(set (match_dup 4) + (lshiftrt:DI (match_dup 2) (match_dup 3))) + (set (pc) + (if_then_else (match_op_dup 1 + [(zero_extract:DI (match_dup 4) + (const_int 1) + (const_int 0)) + (const_int 0)]) + (label_ref (match_dup 0)) + (pc)))] + "") + +;; The following are the corresponding floating-point insns. Recall +;; we need to have variants that expand the arguments from SFmode +;; to DFmode. + +(define_insn "*cmpdf_ieee" + [(set (match_operand:DF 0 "register_operand" "=&f") + (match_operator:DF 1 "alpha_fp_comparison_operator" + [(match_operand:DF 2 "reg_or_0_operand" "fG") + (match_operand:DF 3 "reg_or_0_operand" "fG")]))] + "TARGET_FP && alpha_fptm >= ALPHA_FPTM_SU" + "cmp%-%C1%/ %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "trap_suffix" "su")]) + +(define_insn "*cmpdf_internal" + [(set (match_operand:DF 0 "register_operand" "=f") + (match_operator:DF 1 "alpha_fp_comparison_operator" + [(match_operand:DF 2 "reg_or_0_operand" "fG") + (match_operand:DF 3 "reg_or_0_operand" "fG")]))] + "TARGET_FP" + "cmp%-%C1%/ %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "trap_suffix" "su")]) + +(define_insn "*cmpdf_ext1" + [(set (match_operand:DF 0 "register_operand" "=f") + (match_operator:DF 1 "alpha_fp_comparison_operator" + [(float_extend:DF + (match_operand:SF 2 "reg_or_0_operand" "fG")) + (match_operand:DF 3 "reg_or_0_operand" "fG")]))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "cmp%-%C1%/ %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "trap_suffix" "su")]) + +(define_insn "*cmpdf_ext2" + [(set (match_operand:DF 0 "register_operand" "=f") + (match_operator:DF 1 "alpha_fp_comparison_operator" + [(match_operand:DF 2 "reg_or_0_operand" "fG") + (float_extend:DF + (match_operand:SF 3 "reg_or_0_operand" "fG"))]))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "cmp%-%C1%/ %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "trap_suffix" "su")]) + +(define_insn "*cmpdf_ext3" + [(set (match_operand:DF 0 "register_operand" "=f") + (match_operator:DF 1 "alpha_fp_comparison_operator" + [(float_extend:DF + (match_operand:SF 2 "reg_or_0_operand" "fG")) + (float_extend:DF + (match_operand:SF 3 "reg_or_0_operand" "fG"))]))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "cmp%-%C1%/ %R2,%R3,%0" + [(set_attr "type" "fadd") + (set_attr "trap" "yes") + (set_attr "trap_suffix" "su")]) + +(define_insn "*movdfcc_internal" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (if_then_else:DF + (match_operator 3 "signed_comparison_operator" + [(match_operand:DF 4 "reg_or_0_operand" "fG,fG") + (match_operand:DF 2 "const0_operand" "G,G")]) + (match_operand:DF 1 "reg_or_0_operand" "fG,0") + (match_operand:DF 5 "reg_or_0_operand" "0,fG")))] + "TARGET_FP" + "@ + fcmov%C3 %R4,%R1,%0 + fcmov%D3 %R4,%R5,%0" + [(set_attr "type" "fcmov")]) + +(define_insn "*movsfcc_internal" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (if_then_else:SF + (match_operator 3 "signed_comparison_operator" + [(match_operand:DF 4 "reg_or_0_operand" "fG,fG") + (match_operand:DF 2 "const0_operand" "G,G")]) + (match_operand:SF 1 "reg_or_0_operand" "fG,0") + (match_operand:SF 5 "reg_or_0_operand" "0,fG")))] + "TARGET_FP" + "@ + fcmov%C3 %R4,%R1,%0 + fcmov%D3 %R4,%R5,%0" + [(set_attr "type" "fcmov")]) + +(define_insn "*movdfcc_ext1" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (if_then_else:DF + (match_operator 3 "signed_comparison_operator" + [(match_operand:DF 4 "reg_or_0_operand" "fG,fG") + (match_operand:DF 2 "const0_operand" "G,G")]) + (float_extend:DF (match_operand:SF 1 "reg_or_0_operand" "fG,0")) + (match_operand:DF 5 "reg_or_0_operand" "0,fG")))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "@ + fcmov%C3 %R4,%R1,%0 + fcmov%D3 %R4,%R5,%0" + [(set_attr "type" "fcmov")]) + +(define_insn "*movdfcc_ext2" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (if_then_else:DF + (match_operator 3 "signed_comparison_operator" + [(float_extend:DF + (match_operand:SF 4 "reg_or_0_operand" "fG,fG")) + (match_operand:DF 2 "const0_operand" "G,G")]) + (match_operand:DF 1 "reg_or_0_operand" "fG,0") + (match_operand:DF 5 "reg_or_0_operand" "0,fG")))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "@ + fcmov%C3 %R4,%R1,%0 + fcmov%D3 %R4,%R5,%0" + [(set_attr "type" "fcmov")]) + +(define_insn "*movdfcc_ext3" + [(set (match_operand:SF 0 "register_operand" "=f,f") + (if_then_else:SF + (match_operator 3 "signed_comparison_operator" + [(float_extend:DF + (match_operand:SF 4 "reg_or_0_operand" "fG,fG")) + (match_operand:DF 2 "const0_operand" "G,G")]) + (match_operand:SF 1 "reg_or_0_operand" "fG,0") + (match_operand:SF 5 "reg_or_0_operand" "0,fG")))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "@ + fcmov%C3 %R4,%R1,%0 + fcmov%D3 %R4,%R5,%0" + [(set_attr "type" "fcmov")]) + +(define_insn "*movdfcc_ext4" + [(set (match_operand:DF 0 "register_operand" "=f,f") + (if_then_else:DF + (match_operator 3 "signed_comparison_operator" + [(float_extend:DF + (match_operand:SF 4 "reg_or_0_operand" "fG,fG")) + (match_operand:DF 2 "const0_operand" "G,G")]) + (float_extend:DF (match_operand:SF 1 "reg_or_0_operand" "fG,0")) + (match_operand:DF 5 "reg_or_0_operand" "0,fG")))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" + "@ + fcmov%C3 %R4,%R1,%0 + fcmov%D3 %R4,%R5,%0" + [(set_attr "type" "fcmov")]) + +(define_expand "smaxdf3" + [(set (match_dup 3) + (le:DF (match_operand:DF 1 "reg_or_0_operand" "") + (match_operand:DF 2 "reg_or_0_operand" ""))) + (set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (eq (match_dup 3) (match_dup 4)) + (match_dup 1) (match_dup 2)))] + "TARGET_FP" +{ + operands[3] = gen_reg_rtx (DFmode); + operands[4] = CONST0_RTX (DFmode); +}) + +(define_expand "smindf3" + [(set (match_dup 3) + (lt:DF (match_operand:DF 1 "reg_or_0_operand" "") + (match_operand:DF 2 "reg_or_0_operand" ""))) + (set (match_operand:DF 0 "register_operand" "") + (if_then_else:DF (ne (match_dup 3) (match_dup 4)) + (match_dup 1) (match_dup 2)))] + "TARGET_FP" +{ + operands[3] = gen_reg_rtx (DFmode); + operands[4] = CONST0_RTX (DFmode); +}) + +(define_expand "smaxsf3" + [(set (match_dup 3) + (le:DF (float_extend:DF (match_operand:SF 1 "reg_or_0_operand" "")) + (float_extend:DF (match_operand:SF 2 "reg_or_0_operand" "")))) + (set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (eq (match_dup 3) (match_dup 4)) + (match_dup 1) (match_dup 2)))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" +{ + operands[3] = gen_reg_rtx (DFmode); + operands[4] = CONST0_RTX (DFmode); +}) + +(define_expand "sminsf3" + [(set (match_dup 3) + (lt:DF (float_extend:DF (match_operand:SF 1 "reg_or_0_operand" "")) + (float_extend:DF (match_operand:SF 2 "reg_or_0_operand" "")))) + (set (match_operand:SF 0 "register_operand" "") + (if_then_else:SF (ne (match_dup 3) (match_dup 4)) + (match_dup 1) (match_dup 2)))] + "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU" +{ + operands[3] = gen_reg_rtx (DFmode); + operands[4] = CONST0_RTX (DFmode); +}) + +(define_insn "*fbcc_normal" + [(set (pc) + (if_then_else + (match_operator 1 "signed_comparison_operator" + [(match_operand:DF 2 "reg_or_0_operand" "fG") + (match_operand:DF 3 "const0_operand" "G")]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "TARGET_FP" + "fb%C1 %R2,%0" + [(set_attr "type" "fbr")]) + +(define_insn "*fbcc_ext_normal" + [(set (pc) + (if_then_else + (match_operator 1 "signed_comparison_operator" + [(float_extend:DF + (match_operand:SF 2 "reg_or_0_operand" "fG")) + (match_operand:DF 3 "const0_operand" "G")]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "TARGET_FP" + "fb%C1 %R2,%0" + [(set_attr "type" "fbr")]) + +;; These are the main define_expand's used to make conditional branches +;; and compares. + +(define_expand "cbranchdf4" + [(use (match_operator 0 "alpha_cbranch_operator" + [(match_operand:DF 1 "reg_or_0_operand" "") + (match_operand:DF 2 "reg_or_0_operand" "")])) + (use (match_operand 3 ""))] + "TARGET_FP" + { alpha_emit_conditional_branch (operands, DFmode); DONE; }) + +(define_expand "cbranchtf4" + [(use (match_operator 0 "alpha_cbranch_operator" + [(match_operand:TF 1 "general_operand") + (match_operand:TF 2 "general_operand")])) + (use (match_operand 3 ""))] + "TARGET_HAS_XFLOATING_LIBS" + { alpha_emit_conditional_branch (operands, TFmode); DONE; }) + +(define_expand "cbranchdi4" + [(use (match_operator 0 "alpha_cbranch_operator" + [(match_operand:DI 1 "some_operand") + (match_operand:DI 2 "some_operand")])) + (use (match_operand 3 ""))] + "" + { alpha_emit_conditional_branch (operands, DImode); DONE; }) + +(define_expand "cstoredf4" + [(use (match_operator:DI 1 "alpha_cbranch_operator" + [(match_operand:DF 2 "reg_or_0_operand") + (match_operand:DF 3 "reg_or_0_operand")])) + (clobber (match_operand:DI 0 "register_operand"))] + "TARGET_FP" + { if (!alpha_emit_setcc (operands, DFmode)) FAIL; else DONE; }) + +(define_expand "cstoretf4" + [(use (match_operator:DI 1 "alpha_cbranch_operator" + [(match_operand:TF 2 "general_operand") + (match_operand:TF 3 "general_operand")])) + (clobber (match_operand:DI 0 "register_operand"))] + "TARGET_HAS_XFLOATING_LIBS" + { if (!alpha_emit_setcc (operands, TFmode)) FAIL; else DONE; }) + +(define_expand "cstoredi4" + [(use (match_operator:DI 1 "alpha_cbranch_operator" + [(match_operand:DI 2 "some_operand") + (match_operand:DI 3 "some_operand")])) + (clobber (match_operand:DI 0 "register_operand"))] + "" + { if (!alpha_emit_setcc (operands, DImode)) FAIL; else DONE; }) + +;; These are the main define_expand's used to make conditional moves. + +(define_expand "movsicc" + [(set (match_operand:SI 0 "register_operand" "") + (if_then_else:SI (match_operand 1 "comparison_operator" "") + (match_operand:SI 2 "reg_or_8bit_operand" "") + (match_operand:SI 3 "reg_or_8bit_operand" "")))] + "" +{ + if ((operands[1] = alpha_emit_conditional_move (operands[1], SImode)) == 0) + FAIL; +}) + +(define_expand "movdicc" + [(set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI (match_operand 1 "comparison_operator" "") + (match_operand:DI 2 "reg_or_8bit_operand" "") + (match_operand:DI 3 "reg_or_8bit_operand" "")))] + "" +{ + if ((operands[1] = alpha_emit_conditional_move (operands[1], DImode)) == 0) + FAIL; +}) + +(define_expand "movsfcc" + [(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" "")))] + "" +{ + if ((operands[1] = alpha_emit_conditional_move (operands[1], SFmode)) == 0) + FAIL; +}) + +(define_expand "movdfcc" + [(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" "")))] + "" +{ + if ((operands[1] = alpha_emit_conditional_move (operands[1], DFmode)) == 0) + FAIL; +}) + +;; These define_split definitions are used in cases when comparisons have +;; not be stated in the correct way and we need to reverse the second +;; comparison. For example, x >= 7 has to be done as x < 6 with the +;; comparison that tests the result being reversed. We have one define_split +;; for each use of a comparison. They do not match valid insns and need +;; not generate valid insns. +;; +;; We can also handle equality comparisons (and inequality comparisons in +;; cases where the resulting add cannot overflow) by doing an add followed by +;; a comparison with zero. This is faster since the addition takes one +;; less cycle than a compare when feeding into a conditional move. +;; For this case, we also have an SImode pattern since we can merge the add +;; and sign extend and the order doesn't matter. +;; +;; We do not do this for floating-point, since it isn't clear how the "wrong" +;; operation could have been generated. + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI + (match_operator 1 "comparison_operator" + [(match_operand:DI 2 "reg_or_0_operand" "") + (match_operand:DI 3 "reg_or_cint_operand" "")]) + (match_operand:DI 4 "reg_or_cint_operand" "") + (match_operand:DI 5 "reg_or_cint_operand" ""))) + (clobber (match_operand:DI 6 "register_operand" ""))] + "operands[3] != const0_rtx" + [(set (match_dup 6) (match_dup 7)) + (set (match_dup 0) + (if_then_else:DI (match_dup 8) (match_dup 4) (match_dup 5)))] +{ + enum rtx_code code = GET_CODE (operands[1]); + int unsignedp = (code == GEU || code == LEU || code == GTU || code == LTU); + + /* If we are comparing for equality with a constant and that constant + appears in the arm when the register equals the constant, use the + register since that is more likely to match (and to produce better code + if both would). */ + + if (code == EQ && CONST_INT_P (operands[3]) + && rtx_equal_p (operands[4], operands[3])) + operands[4] = operands[2]; + + else if (code == NE && CONST_INT_P (operands[3]) + && rtx_equal_p (operands[5], operands[3])) + operands[5] = operands[2]; + + if (code == NE || code == EQ + || (extended_count (operands[2], DImode, unsignedp) >= 1 + && extended_count (operands[3], DImode, unsignedp) >= 1)) + { + if (CONST_INT_P (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[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_fmt_ee (code, DImode, operands[2], operands[3]); + operands[8] = gen_rtx_NE (VOIDmode, operands[6], const0_rtx); + } + else + { + operands[7] = gen_rtx_fmt_ee (reverse_condition (code), DImode, + operands[2], operands[3]); + operands[8] = gen_rtx_EQ (VOIDmode, operands[6], const0_rtx); + } +}) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (if_then_else:DI + (match_operator 1 "comparison_operator" + [(match_operand:SI 2 "reg_or_0_operand" "") + (match_operand:SI 3 "reg_or_cint_operand" "")]) + (match_operand:DI 4 "reg_or_8bit_operand" "") + (match_operand:DI 5 "reg_or_8bit_operand" ""))) + (clobber (match_operand:DI 6 "register_operand" ""))] + "operands[3] != const0_rtx + && (GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE)" + [(set (match_dup 6) (match_dup 7)) + (set (match_dup 0) + (if_then_else:DI (match_dup 8) (match_dup 4) (match_dup 5)))] +{ + enum rtx_code code = GET_CODE (operands[1]); + int unsignedp = (code == GEU || code == LEU || code == GTU || code == LTU); + rtx tem; + + if ((code != NE && code != EQ + && ! (extended_count (operands[2], DImode, unsignedp) >= 1 + && extended_count (operands[3], DImode, unsignedp) >= 1))) + FAIL; + + if (CONST_INT_P (operands[3])) + tem = gen_rtx_PLUS (SImode, operands[2], + GEN_INT (- INTVAL (operands[3]))); + else + tem = gen_rtx_MINUS (SImode, operands[2], operands[3]); + + operands[7] = gen_rtx_SIGN_EXTEND (DImode, tem); + operands[8] = gen_rtx_fmt_ee (GET_CODE (operands[1]), VOIDmode, + operands[6], const0_rtx); +}) + +;; Prefer to use cmp and arithmetic when possible instead of a cmove. + +(define_split + [(set (match_operand 0 "register_operand" "") + (if_then_else (match_operator 1 "signed_comparison_operator" + [(match_operand:DI 2 "reg_or_0_operand" "") + (const_int 0)]) + (match_operand 3 "const_int_operand" "") + (match_operand 4 "const_int_operand" "")))] + "" + [(const_int 0)] +{ + if (alpha_split_conditional_move (GET_CODE (operands[1]), operands[0], + operands[2], operands[3], operands[4])) + DONE; + else + FAIL; +}) + +;; ??? Why combine is allowed to create such non-canonical rtl, I don't know. +;; Oh well, we match it in movcc, so it must be partially our fault. +(define_split + [(set (match_operand 0 "register_operand" "") + (if_then_else (match_operator 1 "signed_comparison_operator" + [(const_int 0) + (match_operand:DI 2 "reg_or_0_operand" "")]) + (match_operand 3 "const_int_operand" "") + (match_operand 4 "const_int_operand" "")))] + "" + [(const_int 0)] +{ + if (alpha_split_conditional_move (swap_condition (GET_CODE (operands[1])), + operands[0], operands[2], operands[3], + operands[4])) + DONE; + else + FAIL; +}) + +(define_insn_and_split "*cmp_sadd_di" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (if_then_else:DI + (match_operator 1 "alpha_zero_comparison_operator" + [(match_operand:DI 2 "reg_or_0_operand" "rJ") + (const_int 0)]) + (match_operand:DI 3 "const48_operand" "I") + (const_int 0)) + (match_operand:DI 4 "sext_add_operand" "rIO"))) + (clobber (match_scratch:DI 5 "=r"))] + "" + "#" + "" + [(set (match_dup 5) + (match_op_dup:DI 1 [(match_dup 2) (const_int 0)])) + (set (match_dup 0) + (plus:DI (mult:DI (match_dup 5) (match_dup 3)) + (match_dup 4)))] +{ + if (can_create_pseudo_p ()) + operands[5] = gen_reg_rtx (DImode); + else if (reg_overlap_mentioned_p (operands[5], operands[4])) + operands[5] = operands[0]; +}) + +(define_insn_and_split "*cmp_sadd_si" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (if_then_else:SI + (match_operator 1 "alpha_zero_comparison_operator" + [(match_operand:DI 2 "reg_or_0_operand" "rJ") + (const_int 0)]) + (match_operand:SI 3 "const48_operand" "I") + (const_int 0)) + (match_operand:SI 4 "sext_add_operand" "rIO"))) + (clobber (match_scratch:DI 5 "=r"))] + "" + "#" + "" + [(set (match_dup 5) + (match_op_dup:DI 1 [(match_dup 2) (const_int 0)])) + (set (match_dup 0) + (plus:SI (mult:SI (match_dup 6) (match_dup 3)) + (match_dup 4)))] +{ + if (can_create_pseudo_p ()) + operands[5] = gen_reg_rtx (DImode); + else if (reg_overlap_mentioned_p (operands[5], operands[4])) + operands[5] = gen_lowpart (DImode, operands[0]); + + operands[6] = gen_lowpart (SImode, operands[5]); +}) + +(define_insn_and_split "*cmp_sadd_sidi" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (plus:SI (if_then_else:SI + (match_operator 1 "alpha_zero_comparison_operator" + [(match_operand:DI 2 "reg_or_0_operand" "rJ") + (const_int 0)]) + (match_operand:SI 3 "const48_operand" "I") + (const_int 0)) + (match_operand:SI 4 "sext_add_operand" "rIO")))) + (clobber (match_scratch:DI 5 "=r"))] + "" + "#" + "" + [(set (match_dup 5) + (match_op_dup:DI 1 [(match_dup 2) (const_int 0)])) + (set (match_dup 0) + (sign_extend:DI (plus:SI (mult:SI (match_dup 6) (match_dup 3)) + (match_dup 4))))] +{ + if (can_create_pseudo_p ()) + operands[5] = gen_reg_rtx (DImode); + else if (reg_overlap_mentioned_p (operands[5], operands[4])) + operands[5] = operands[0]; + + operands[6] = gen_lowpart (SImode, operands[5]); +}) + +(define_insn_and_split "*cmp_ssub_di" + [(set (match_operand:DI 0 "register_operand" "=r") + (minus:DI (if_then_else:DI + (match_operator 1 "alpha_zero_comparison_operator" + [(match_operand:DI 2 "reg_or_0_operand" "rJ") + (const_int 0)]) + (match_operand:DI 3 "const48_operand" "I") + (const_int 0)) + (match_operand:DI 4 "reg_or_8bit_operand" "rI"))) + (clobber (match_scratch:DI 5 "=r"))] + "" + "#" + "" + [(set (match_dup 5) + (match_op_dup:DI 1 [(match_dup 2) (const_int 0)])) + (set (match_dup 0) + (minus:DI (mult:DI (match_dup 5) (match_dup 3)) + (match_dup 4)))] +{ + if (can_create_pseudo_p ()) + operands[5] = gen_reg_rtx (DImode); + else if (reg_overlap_mentioned_p (operands[5], operands[4])) + operands[5] = operands[0]; +}) + +(define_insn_and_split "*cmp_ssub_si" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (if_then_else:SI + (match_operator 1 "alpha_zero_comparison_operator" + [(match_operand:DI 2 "reg_or_0_operand" "rJ") + (const_int 0)]) + (match_operand:SI 3 "const48_operand" "I") + (const_int 0)) + (match_operand:SI 4 "reg_or_8bit_operand" "rI"))) + (clobber (match_scratch:DI 5 "=r"))] + "" + "#" + "" + [(set (match_dup 5) + (match_op_dup:DI 1 [(match_dup 2) (const_int 0)])) + (set (match_dup 0) + (minus:SI (mult:SI (match_dup 6) (match_dup 3)) + (match_dup 4)))] +{ + if (can_create_pseudo_p ()) + operands[5] = gen_reg_rtx (DImode); + else if (reg_overlap_mentioned_p (operands[5], operands[4])) + operands[5] = gen_lowpart (DImode, operands[0]); + + operands[6] = gen_lowpart (SImode, operands[5]); +}) + +(define_insn_and_split "*cmp_ssub_sidi" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (minus:SI (if_then_else:SI + (match_operator 1 "alpha_zero_comparison_operator" + [(match_operand:DI 2 "reg_or_0_operand" "rJ") + (const_int 0)]) + (match_operand:SI 3 "const48_operand" "I") + (const_int 0)) + (match_operand:SI 4 "reg_or_8bit_operand" "rI")))) + (clobber (match_scratch:DI 5 "=r"))] + "" + "#" + "" + [(set (match_dup 5) + (match_op_dup:DI 1 [(match_dup 2) (const_int 0)])) + (set (match_dup 0) + (sign_extend:DI (minus:SI (mult:SI (match_dup 6) (match_dup 3)) + (match_dup 4))))] +{ + if (can_create_pseudo_p ()) + operands[5] = gen_reg_rtx (DImode); + else if (reg_overlap_mentioned_p (operands[5], operands[4])) + operands[5] = operands[0]; + + operands[6] = gen_lowpart (SImode, operands[5]); +}) + +;; Here are the CALL and unconditional branch insns. Calls on NT and OSF +;; work differently, so we have different patterns for each. + +;; On Unicos/Mk a call information word (CIW) must be generated for each +;; call. The CIW contains information about arguments passed in registers +;; and is stored in the caller's SSIB. Its offset relative to the beginning +;; of the SSIB is passed in $25. Handling this properly is quite complicated +;; in the presence of inlining since the CIWs for calls performed by the +;; inlined function must be stored in the SSIB of the function it is inlined +;; into as well. We encode the CIW in an unspec and append it to the list +;; of the CIWs for the current function only when the instruction for loading +;; $25 is generated. + +(define_expand "call" + [(use (match_operand:DI 0 "" "")) + (use (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" ""))] + "" +{ + if (TARGET_ABI_WINDOWS_NT) + emit_call_insn (gen_call_nt (operands[0], operands[1])); + else if (TARGET_ABI_OPEN_VMS) + emit_call_insn (gen_call_vms (operands[0], operands[2])); + else if (TARGET_ABI_UNICOSMK) + emit_call_insn (gen_call_umk (operands[0], operands[2])); + else + emit_call_insn (gen_call_osf (operands[0], operands[1])); + DONE; +}) + +(define_expand "sibcall" + [(parallel [(call (mem:DI (match_operand 0 "" "")) + (match_operand 1 "" "")) + (unspec [(reg:DI 29)] UNSPEC_SIBCALL)])] + "TARGET_ABI_OSF" +{ + gcc_assert (MEM_P (operands[0])); + operands[0] = XEXP (operands[0], 0); +}) + +(define_expand "call_osf" + [(parallel [(call (mem:DI (match_operand 0 "" "")) + (match_operand 1 "" "")) + (use (reg:DI 29)) + (clobber (reg:DI 26))])] + "" +{ + gcc_assert (MEM_P (operands[0])); + + operands[0] = XEXP (operands[0], 0); + if (! call_operand (operands[0], Pmode)) + operands[0] = copy_to_mode_reg (Pmode, operands[0]); +}) + +(define_expand "call_nt" + [(parallel [(call (mem:DI (match_operand 0 "" "")) + (match_operand 1 "" "")) + (clobber (reg:DI 26))])] + "" +{ + gcc_assert (MEM_P (operands[0])); + + operands[0] = XEXP (operands[0], 0); + if (GET_CODE (operands[0]) != SYMBOL_REF && !REG_P (operands[0])) + operands[0] = force_reg (DImode, operands[0]); +}) + +;; Calls on Unicos/Mk are always indirect. +;; op 0: symbol ref for called function +;; op 1: CIW for $25 represented by an unspec + +(define_expand "call_umk" + [(parallel [(call (mem:DI (match_operand 0 "" "")) + (match_operand 1 "" "")) + (use (reg:DI 25)) + (clobber (reg:DI 26))])] + "" +{ + gcc_assert (MEM_P (operands[0])); + + /* Always load the address of the called function into a register; + load the CIW in $25. */ + + operands[0] = XEXP (operands[0], 0); + if (!REG_P (operands[0])) + operands[0] = force_reg (DImode, operands[0]); + + emit_move_insn (gen_rtx_REG (DImode, 25), operands[1]); +}) + +;; +;; 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))])] + "" +{ + gcc_assert (MEM_P (operands[0])); + + 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) + { + alpha_need_linkage (XSTR (operands[0], 0), 0); + + operands[2] = const0_rtx; + } + 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 3 "" "")) + (use (match_operand 4 "" ""))] + "" +{ + if (TARGET_ABI_WINDOWS_NT) + emit_call_insn (gen_call_value_nt (operands[0], operands[1], operands[2])); + else if (TARGET_ABI_OPEN_VMS) + emit_call_insn (gen_call_value_vms (operands[0], operands[1], + operands[3])); + else if (TARGET_ABI_UNICOSMK) + emit_call_insn (gen_call_value_umk (operands[0], operands[1], + operands[3])); + else + emit_call_insn (gen_call_value_osf (operands[0], operands[1], + operands[2])); + DONE; +}) + +(define_expand "sibcall_value" + [(parallel [(set (match_operand 0 "" "") + (call (mem:DI (match_operand 1 "" "")) + (match_operand 2 "" ""))) + (unspec [(reg:DI 29)] UNSPEC_SIBCALL)])] + "TARGET_ABI_OSF" +{ + gcc_assert (MEM_P (operands[1])); + operands[1] = XEXP (operands[1], 0); +}) + +(define_expand "call_value_osf" + [(parallel [(set (match_operand 0 "" "") + (call (mem:DI (match_operand 1 "" "")) + (match_operand 2 "" ""))) + (use (reg:DI 29)) + (clobber (reg:DI 26))])] + "" +{ + gcc_assert (MEM_P (operands[1])); + + operands[1] = XEXP (operands[1], 0); + if (! call_operand (operands[1], Pmode)) + operands[1] = copy_to_mode_reg (Pmode, operands[1]); +}) + +(define_expand "call_value_nt" + [(parallel [(set (match_operand 0 "" "") + (call (mem:DI (match_operand 1 "" "")) + (match_operand 2 "" ""))) + (clobber (reg:DI 26))])] + "" +{ + gcc_assert (MEM_P (operands[1])); + + operands[1] = XEXP (operands[1], 0); + if (GET_CODE (operands[1]) != SYMBOL_REF && !REG_P (operands[1])) + 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))])] + "" +{ + gcc_assert (MEM_P (operands[1])); + + 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) + { + alpha_need_linkage (XSTR (operands[1], 0), 0); + + operands[3] = const0_rtx; + } + else + { + emit_move_insn (gen_rtx_REG (Pmode, 26), + gen_rtx_MEM (Pmode, plus_constant (operands[1], 8))); + operands[3] = operands[1]; + } +}) + +(define_expand "call_value_umk" + [(parallel [(set (match_operand 0 "" "") + (call (mem:DI (match_operand 1 "" "")) + (match_operand 2 "" ""))) + (use (reg:DI 25)) + (clobber (reg:DI 26))])] + "" +{ + gcc_assert (MEM_P (operands[1])); + + operands[1] = XEXP (operands[1], 0); + if (!REG_P (operands[1])) + operands[1] = force_reg (DImode, operands[1]); + + emit_move_insn (gen_rtx_REG (DImode, 25), operands[2]); +}) + +(define_insn "*call_osf_1_er_noreturn" + [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,s")) + (match_operand 1 "" "")) + (use (reg:DI 29)) + (clobber (reg:DI 26))] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF + && find_reg_note (insn, REG_NORETURN, NULL_RTX)" + "@ + jsr $26,($27),0 + bsr $26,%0\t\t!samegp + ldq $27,%0($29)\t\t!literal!%#\;jsr $26,($27),%0\t\t!lituse_jsr!%#" + [(set_attr "type" "jsr") + (set_attr "length" "*,*,8")]) + +(define_insn "*call_osf_1_er" + [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,s")) + (match_operand 1 "" "")) + (use (reg:DI 29)) + (clobber (reg:DI 26))] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "@ + jsr $26,(%0),0\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%* + bsr $26,%0\t\t!samegp + ldq $27,%0($29)\t\t!literal!%#\;jsr $26,($27),%0\t\t!lituse_jsr!%#\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*" + [(set_attr "type" "jsr") + (set_attr "length" "12,*,16")]) + +;; We must use peep2 instead of a split because we need accurate life +;; information for $gp. Consider the case of { bar(); while (1); }. +(define_peephole2 + [(parallel [(call (mem:DI (match_operand:DI 0 "call_operand" "")) + (match_operand 1 "" "")) + (use (reg:DI 29)) + (clobber (reg:DI 26))])] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF && reload_completed + && ! samegp_function_operand (operands[0], Pmode) + && (peep2_regno_dead_p (1, 29) + || find_reg_note (insn, REG_NORETURN, NULL_RTX))" + [(parallel [(call (mem:DI (match_dup 2)) + (match_dup 1)) + (use (reg:DI 29)) + (use (match_dup 0)) + (use (match_dup 3)) + (clobber (reg:DI 26))])] +{ + if (CONSTANT_P (operands[0])) + { + operands[2] = gen_rtx_REG (Pmode, 27); + operands[3] = GEN_INT (alpha_next_sequence_number++); + emit_insn (gen_movdi_er_high_g (operands[2], pic_offset_table_rtx, + operands[0], operands[3])); + } + else + { + operands[2] = operands[0]; + operands[0] = const0_rtx; + operands[3] = const0_rtx; + } +}) + +(define_peephole2 + [(parallel [(call (mem:DI (match_operand:DI 0 "call_operand" "")) + (match_operand 1 "" "")) + (use (reg:DI 29)) + (clobber (reg:DI 26))])] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF && reload_completed + && ! samegp_function_operand (operands[0], Pmode) + && ! (peep2_regno_dead_p (1, 29) + || find_reg_note (insn, REG_NORETURN, NULL_RTX))" + [(parallel [(call (mem:DI (match_dup 2)) + (match_dup 1)) + (set (match_dup 5) + (unspec:DI [(match_dup 5) (match_dup 3)] UNSPEC_LDGP1)) + (use (match_dup 0)) + (use (match_dup 4)) + (clobber (reg:DI 26))]) + (set (match_dup 5) + (unspec:DI [(match_dup 5) (match_dup 3)] UNSPEC_LDGP2))] +{ + if (CONSTANT_P (operands[0])) + { + operands[2] = gen_rtx_REG (Pmode, 27); + operands[4] = GEN_INT (alpha_next_sequence_number++); + emit_insn (gen_movdi_er_high_g (operands[2], pic_offset_table_rtx, + operands[0], operands[4])); + } + else + { + operands[2] = operands[0]; + operands[0] = const0_rtx; + operands[4] = const0_rtx; + } + operands[3] = GEN_INT (alpha_next_sequence_number++); + operands[5] = pic_offset_table_rtx; +}) + +(define_insn "*call_osf_2_er_nogp" + [(call (mem:DI (match_operand:DI 0 "register_operand" "c")) + (match_operand 1 "" "")) + (use (reg:DI 29)) + (use (match_operand 2 "" "")) + (use (match_operand 3 "const_int_operand" "")) + (clobber (reg:DI 26))] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "jsr $26,(%0),%2%J3" + [(set_attr "type" "jsr")]) + +(define_insn "*call_osf_2_er" + [(call (mem:DI (match_operand:DI 0 "register_operand" "c")) + (match_operand 1 "" "")) + (set (reg:DI 29) + (unspec:DI [(reg:DI 29) (match_operand 4 "const_int_operand" "")] + UNSPEC_LDGP1)) + (use (match_operand 2 "" "")) + (use (match_operand 3 "const_int_operand" "")) + (clobber (reg:DI 26))] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "jsr $26,(%0),%2%J3\;ldah $29,0($26)\t\t!gpdisp!%4" + [(set_attr "type" "jsr") + (set_attr "cannot_copy" "true") + (set_attr "length" "8")]) + +(define_insn "*call_osf_1_noreturn" + [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,s")) + (match_operand 1 "" "")) + (use (reg:DI 29)) + (clobber (reg:DI 26))] + "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF + && find_reg_note (insn, REG_NORETURN, NULL_RTX)" + "@ + jsr $26,($27),0 + bsr $26,$%0..ng + jsr $26,%0" + [(set_attr "type" "jsr") + (set_attr "length" "*,*,8")]) + +(define_insn "*call_osf_1" + [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,s")) + (match_operand 1 "" "")) + (use (reg:DI 29)) + (clobber (reg:DI 26))] + "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "@ + jsr $26,($27),0\;ldgp $29,0($26) + bsr $26,$%0..ng + jsr $26,%0\;ldgp $29,0($26)" + [(set_attr "type" "jsr") + (set_attr "length" "12,*,16")]) + +(define_insn "*sibcall_osf_1_er" + [(call (mem:DI (match_operand:DI 0 "symbolic_operand" "R,s")) + (match_operand 1 "" "")) + (unspec [(reg:DI 29)] UNSPEC_SIBCALL)] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "@ + br $31,%0\t\t!samegp + ldq $27,%0($29)\t\t!literal!%#\;jmp $31,($27),%0\t\t!lituse_jsr!%#" + [(set_attr "type" "jsr") + (set_attr "length" "*,8")]) + +;; Note that the DEC assembler expands "jmp foo" with $at, which +;; doesn't do what we want. +(define_insn "*sibcall_osf_1" + [(call (mem:DI (match_operand:DI 0 "symbolic_operand" "R,s")) + (match_operand 1 "" "")) + (unspec [(reg:DI 29)] UNSPEC_SIBCALL)] + "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "@ + br $31,$%0..ng + lda $27,%0\;jmp $31,($27),%0" + [(set_attr "type" "jsr") + (set_attr "length" "*,8")]) + +(define_insn "*call_nt_1" + [(call (mem:DI (match_operand:DI 0 "call_operand" "r,R,s")) + (match_operand 1 "" "")) + (clobber (reg:DI 26))] + "TARGET_ABI_WINDOWS_NT" + "@ + jsr $26,(%0) + bsr $26,%0 + jsr $26,%0" + [(set_attr "type" "jsr") + (set_attr "length" "*,*,12")]) + +; GAS relies on the order and position of instructions output below in order +; to generate relocs for VMS link to potentially optimize the call. +; Please do not molest. +(define_insn "*call_vms_1" + [(call (mem:DI (match_operand:DI 0 "call_operand" "r,s")) + (match_operand 1 "" "")) + (use (match_operand:DI 2 "nonmemory_operand" "r,n")) + (use (reg:DI 25)) + (use (reg:DI 26)) + (clobber (reg:DI 27))] + "TARGET_ABI_OPEN_VMS" +{ + switch (which_alternative) + { + case 0: + return "mov %2,$27\;jsr $26,0\;ldq $27,0($29)"; + case 1: + operands [2] = alpha_use_linkage (operands [0], cfun->decl, 1, 0); + operands [3] = alpha_use_linkage (operands [0], cfun->decl, 0, 0); + return "ldq $26,%3\;ldq $27,%2\;jsr $26,%0\;ldq $27,0($29)"; + default: + gcc_unreachable (); + } +} + [(set_attr "type" "jsr") + (set_attr "length" "12,16")]) + +(define_insn "*call_umk_1" + [(call (mem:DI (match_operand:DI 0 "call_operand" "r")) + (match_operand 1 "" "")) + (use (reg:DI 25)) + (clobber (reg:DI 26))] + "TARGET_ABI_UNICOSMK" + "jsr $26,(%0)" + [(set_attr "type" "jsr")]) + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" +{ + int i; + + emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + + DONE; +}) + +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and +;; all of memory. This blocks insns from being moved across this point. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)] + "" + "" + [(set_attr "length" "0") + (set_attr "type" "none")]) + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "br $31,%l0" + [(set_attr "type" "ibr")]) + +(define_expand "return" + [(return)] + "direct_return ()" + "") + +(define_insn "*return_internal" + [(return)] + "reload_completed" + "ret $31,($26),1" + [(set_attr "type" "ibr")]) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:DI 0 "register_operand" "r"))] + "" + "jmp $31,(%0),0" + [(set_attr "type" "ibr")]) + +(define_expand "tablejump" + [(parallel [(set (pc) + (match_operand 0 "register_operand" "")) + (use (label_ref:DI (match_operand 1 "" "")))])] + "" +{ + if (TARGET_ABI_WINDOWS_NT) + { + rtx dest = gen_reg_rtx (DImode); + emit_insn (gen_extendsidi2 (dest, operands[0])); + operands[0] = dest; + } + else if (TARGET_ABI_OSF) + { + rtx dest = gen_reg_rtx (DImode); + emit_insn (gen_extendsidi2 (dest, operands[0])); + emit_insn (gen_adddi3 (dest, pic_offset_table_rtx, dest)); + operands[0] = dest; + } +}) + +(define_insn "*tablejump_osf_nt_internal" + [(set (pc) + (match_operand:DI 0 "register_operand" "r")) + (use (label_ref:DI (match_operand 1 "" "")))] + "(TARGET_ABI_OSF || TARGET_ABI_WINDOWS_NT) + && alpha_tablejump_addr_vec (insn)" +{ + operands[2] = alpha_tablejump_best_label (insn); + return "jmp $31,(%0),%2"; +} + [(set_attr "type" "ibr")]) + +(define_insn "*tablejump_internal" + [(set (pc) + (match_operand:DI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp $31,(%0),0" + [(set_attr "type" "ibr")]) + +;; Cache flush. Used by alpha_trampoline_init. 0x86 is PAL_imb, but we don't +;; want to have to include pal.h in our .s file. +(define_insn "imb" + [(unspec_volatile [(const_int 0)] UNSPECV_IMB)] + "" + "call_pal 0x86" + [(set_attr "type" "callpal")]) + +;; BUGCHK is documented common to OSF/1 and VMS PALcode. +;; NT does not document anything at 0x81 -- presumably it would generate +;; the equivalent of SIGILL, but this isn't that important. +;; ??? Presuming unicosmk uses either OSF/1 or VMS PALcode. +(define_insn "trap" + [(trap_if (const_int 1) (const_int 0))] + "!TARGET_ABI_WINDOWS_NT" + "call_pal 0x81" + [(set_attr "type" "callpal")]) + +;; For userland, we load the thread pointer from the TCB. +;; For the kernel, we load the per-cpu private value. + +(define_insn "load_tp" + [(set (match_operand:DI 0 "register_operand" "=v") + (unspec:DI [(const_int 0)] UNSPEC_TP))] + "TARGET_ABI_OSF" +{ + if (TARGET_TLS_KERNEL) + return "call_pal 0x32"; + else + return "call_pal 0x9e"; +} + [(set_attr "type" "callpal")]) + +;; For completeness, and possibly a __builtin function, here's how to +;; set the thread pointer. Since we don't describe enough of this +;; quantity for CSE, we have to use a volatile unspec, and then there's +;; not much point in creating an R16_REG register class. + +(define_expand "set_tp" + [(set (reg:DI 16) (match_operand:DI 0 "input_operand" "")) + (unspec_volatile [(reg:DI 16)] UNSPECV_SET_TP)] + "TARGET_ABI_OSF" + "") + +(define_insn "*set_tp" + [(unspec_volatile [(reg:DI 16)] UNSPECV_SET_TP)] + "TARGET_ABI_OSF" +{ + if (TARGET_TLS_KERNEL) + return "call_pal 0x31"; + else + return "call_pal 0x9f"; +} + [(set_attr "type" "callpal")]) + +;; Special builtins for establishing and reverting VMS condition handlers. + +(define_expand "builtin_establish_vms_condition_handler" + [(set (reg:DI 0) (match_operand:DI 0 "register_operand" "")) + (use (match_operand:DI 1 "address_operand" ""))] + "TARGET_ABI_OPEN_VMS" +{ + alpha_expand_builtin_establish_vms_condition_handler (operands[0], + operands[1]); +}) + +(define_expand "builtin_revert_vms_condition_handler" + [(set (reg:DI 0) (match_operand:DI 0 "register_operand" ""))] + "TARGET_ABI_OPEN_VMS" +{ + alpha_expand_builtin_revert_vms_condition_handler (operands[0]); +}) + +;; 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 +;; they are simpler. + +(define_insn "*movsf_nofix" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m") + (match_operand:SF 1 "input_operand" "fG,m,*rG,m,fG,*r"))] + "TARGET_FPREGS && ! TARGET_FIX + && (register_operand (operands[0], SFmode) + || reg_or_0_operand (operands[1], SFmode))" + "@ + cpys %R1,%R1,%0 + ld%, %0,%1 + bis $31,%r1,%0 + ldl %0,%1 + st%, %R1,%0 + stl %r1,%0" + [(set_attr "type" "fcpys,fld,ilog,ild,fst,ist")]) + +(define_insn "*movsf_fix" + [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m,f,*r") + (match_operand:SF 1 "input_operand" "fG,m,*rG,m,fG,*r,*r,f"))] + "TARGET_FPREGS && TARGET_FIX + && (register_operand (operands[0], SFmode) + || reg_or_0_operand (operands[1], SFmode))" + "@ + cpys %R1,%R1,%0 + ld%, %0,%1 + bis $31,%r1,%0 + ldl %0,%1 + st%, %R1,%0 + stl %r1,%0 + itofs %1,%0 + ftois %1,%0" + [(set_attr "type" "fcpys,fld,ilog,ild,fst,ist,itof,ftoi")]) + +(define_insn "*movsf_nofp" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m") + (match_operand:SF 1 "input_operand" "rG,m,r"))] + "! TARGET_FPREGS + && (register_operand (operands[0], SFmode) + || reg_or_0_operand (operands[1], SFmode))" + "@ + bis $31,%r1,%0 + ldl %0,%1 + stl %r1,%0" + [(set_attr "type" "ilog,ild,ist")]) + +(define_insn "*movdf_nofix" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m") + (match_operand:DF 1 "input_operand" "fG,m,*rG,m,fG,*r"))] + "TARGET_FPREGS && ! TARGET_FIX + && (register_operand (operands[0], DFmode) + || reg_or_0_operand (operands[1], DFmode))" + "@ + cpys %R1,%R1,%0 + ld%- %0,%1 + bis $31,%r1,%0 + ldq %0,%1 + st%- %R1,%0 + stq %r1,%0" + [(set_attr "type" "fcpys,fld,ilog,ild,fst,ist")]) + +(define_insn "*movdf_fix" + [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m,f,*r") + (match_operand:DF 1 "input_operand" "fG,m,*rG,m,fG,*r,*r,f"))] + "TARGET_FPREGS && TARGET_FIX + && (register_operand (operands[0], DFmode) + || reg_or_0_operand (operands[1], DFmode))" + "@ + cpys %R1,%R1,%0 + ld%- %0,%1 + bis $31,%r1,%0 + ldq %0,%1 + st%- %R1,%0 + stq %r1,%0 + itoft %1,%0 + ftoit %1,%0" + [(set_attr "type" "fcpys,fld,ilog,ild,fst,ist,itof,ftoi")]) + +(define_insn "*movdf_nofp" + [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m") + (match_operand:DF 1 "input_operand" "rG,m,r"))] + "! TARGET_FPREGS + && (register_operand (operands[0], DFmode) + || reg_or_0_operand (operands[1], DFmode))" + "@ + bis $31,%r1,%0 + ldq %0,%1 + stq %r1,%0" + [(set_attr "type" "ilog,ild,ist")]) + +;; Subregs suck for register allocation. Pretend we can move TFmode +;; data between general registers until after reload. + +(define_insn_and_split "*movtf_internal" + [(set (match_operand:TF 0 "nonimmediate_operand" "=r,o") + (match_operand:TF 1 "input_operand" "roG,rG"))] + "register_operand (operands[0], TFmode) + || reg_or_0_operand (operands[1], TFmode)" + "#" + "reload_completed" + [(set (match_dup 0) (match_dup 2)) + (set (match_dup 1) (match_dup 3))] +{ + alpha_split_tmode_pair (operands, TFmode, true); +}) + +(define_expand "movsf" + [(set (match_operand:SF 0 "nonimmediate_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" +{ + if (MEM_P (operands[0]) + && ! reg_or_0_operand (operands[1], SFmode)) + operands[1] = force_reg (SFmode, operands[1]); +}) + +(define_expand "movdf" + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" +{ + if (MEM_P (operands[0]) + && ! reg_or_0_operand (operands[1], DFmode)) + operands[1] = force_reg (DFmode, operands[1]); +}) + +(define_expand "movtf" + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (match_operand:TF 1 "general_operand" ""))] + "" +{ + if (MEM_P (operands[0]) + && ! reg_or_0_operand (operands[1], TFmode)) + operands[1] = force_reg (TFmode, operands[1]); +}) + +(define_insn "*movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m") + (match_operand:SI 1 "input_operand" "rJ,K,L,n,m,rJ"))] + "(TARGET_ABI_OSF || TARGET_ABI_UNICOSMK) + && (register_operand (operands[0], SImode) + || reg_or_0_operand (operands[1], SImode))" + "@ + bis $31,%r1,%0 + lda %0,%1($31) + ldah %0,%h1($31) + # + ldl %0,%1 + stl %r1,%0" + [(set_attr "type" "ilog,iadd,iadd,multi,ild,ist")]) + +(define_insn "*movsi_nt_vms" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m") + (match_operand:SI 1 "input_operand" "rJ,K,L,s,n,m,rJ"))] + "(TARGET_ABI_WINDOWS_NT || TARGET_ABI_OPEN_VMS) + && (register_operand (operands[0], SImode) + || reg_or_0_operand (operands[1], SImode))" + "@ + bis $31,%1,%0 + lda %0,%1 + ldah %0,%h1 + lda %0,%1 + # + ldl %0,%1 + stl %r1,%0" + [(set_attr "type" "ilog,iadd,iadd,ldsym,multi,ild,ist")]) + +(define_insn "*movhi_nobwx" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (match_operand:HI 1 "input_operand" "rJ,n"))] + "! TARGET_BWX + && (register_operand (operands[0], HImode) + || register_operand (operands[1], HImode))" + "@ + bis $31,%r1,%0 + lda %0,%L1($31)" + [(set_attr "type" "ilog,iadd")]) + +(define_insn "*movhi_bwx" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m") + (match_operand:HI 1 "input_operand" "rJ,n,m,rJ"))] + "TARGET_BWX + && (register_operand (operands[0], HImode) + || reg_or_0_operand (operands[1], HImode))" + "@ + bis $31,%r1,%0 + lda %0,%L1($31) + ldwu %0,%1 + stw %r1,%0" + [(set_attr "type" "ilog,iadd,ild,ist")]) + +(define_insn "*movqi_nobwx" + [(set (match_operand:QI 0 "register_operand" "=r,r") + (match_operand:QI 1 "input_operand" "rJ,n"))] + "! TARGET_BWX + && (register_operand (operands[0], QImode) + || register_operand (operands[1], QImode))" + "@ + bis $31,%r1,%0 + lda %0,%L1($31)" + [(set_attr "type" "ilog,iadd")]) + +(define_insn "*movqi_bwx" + [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m") + (match_operand:QI 1 "input_operand" "rJ,n,m,rJ"))] + "TARGET_BWX + && (register_operand (operands[0], QImode) + || reg_or_0_operand (operands[1], QImode))" + "@ + bis $31,%r1,%0 + lda %0,%L1($31) + ldbu %0,%1 + stb %r1,%0" + [(set_attr "type" "ilog,iadd,ild,ist")]) + +;; We do two major things here: handle mem->mem and construct long +;; constants. + +(define_expand "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" +{ + if (alpha_expand_mov (SImode, operands)) + DONE; +}) + +;; Split a load of a large constant into the appropriate two-insn +;; sequence. + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "non_add_const_operand" ""))] + "" + [(const_int 0)] +{ + if (alpha_split_const_mov (SImode, operands)) + DONE; + else + FAIL; +}) + +;; Split the load of an address into a four-insn sequence on Unicos/Mk. +;; Always generate a REG_EQUAL note for the last instruction to facilitate +;; optimizations. If the symbolic operand is a label_ref, generate +;; REG_LABEL_OPERAND notes and update LABEL_NUSES because this is not done +;; automatically. Labels may be incorrectly deleted if we don't do this. +;; +;; Describing what the individual instructions do correctly is too complicated +;; so use UNSPECs for each of the three parts of an address. + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "symbolic_operand" ""))] + "TARGET_ABI_UNICOSMK && reload_completed" + [(const_int 0)] +{ + rtx insn1, insn2, insn3; + + insn1 = emit_insn (gen_umk_laum (operands[0], operands[1])); + emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32))); + insn2 = emit_insn (gen_umk_lalm (operands[0], operands[0], operands[1])); + insn3 = emit_insn (gen_umk_lal (operands[0], operands[0], operands[1])); + set_unique_reg_note (insn3, REG_EQUAL, operands[1]); + + if (GET_CODE (operands[1]) == LABEL_REF) + { + rtx label; + + label = XEXP (operands[1], 0); + add_reg_note (insn1, REG_LABEL_OPERAND, label); + add_reg_note (insn2, REG_LABEL_OPERAND, label); + add_reg_note (insn3, REG_LABEL_OPERAND, label); + LABEL_NUSES (label) += 3; + } + DONE; +}) + +;; Instructions for loading the three parts of an address on Unicos/Mk. + +(define_insn "umk_laum" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")] + UNSPEC_UMK_LAUM))] + "TARGET_ABI_UNICOSMK" + "laum %r0,%t1($31)" + [(set_attr "type" "iadd")]) + +(define_insn "umk_lalm" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (match_operand:DI 1 "register_operand" "r") + (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")] + UNSPEC_UMK_LALM)))] + "TARGET_ABI_UNICOSMK" + "lalm %r0,%t2(%r1)" + [(set_attr "type" "iadd")]) + +(define_insn "umk_lal" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (match_operand:DI 1 "register_operand" "r") + (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")] + UNSPEC_UMK_LAL)))] + "TARGET_ABI_UNICOSMK" + "lal %r0,%t2(%r1)" + [(set_attr "type" "iadd")]) + +;; Add a new call information word to the current function's list of CIWs +;; and load its index into $25. Doing it here ensures that the CIW will be +;; associated with the correct function even in the presence of inlining. + +(define_insn "*umk_load_ciw" + [(set (reg:DI 25) + (unspec:DI [(match_operand 0 "" "")] UNSPEC_UMK_LOAD_CIW))] + "TARGET_ABI_UNICOSMK" +{ + operands[0] = unicosmk_add_call_info_word (operands[0]); + return "lda $25,%0"; +} + [(set_attr "type" "iadd")]) + +(define_insn "*movdi_er_low_l" + [(set (match_operand:DI 0 "register_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "local_symbolic_operand" "")))] + "TARGET_EXPLICIT_RELOCS" +{ + if (true_regnum (operands[1]) == 29) + return "lda %0,%2(%1)\t\t!gprel"; + else + return "lda %0,%2(%1)\t\t!gprellow"; +} + [(set_attr "usegp" "yes")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "small_symbolic_operand" ""))] + "TARGET_EXPLICIT_RELOCS && reload_completed" + [(set (match_dup 0) + (lo_sum:DI (match_dup 2) (match_dup 1)))] + "operands[2] = pic_offset_table_rtx;") + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "local_symbolic_operand" ""))] + "TARGET_EXPLICIT_RELOCS && reload_completed" + [(set (match_dup 0) + (plus:DI (match_dup 2) (high:DI (match_dup 1)))) + (set (match_dup 0) + (lo_sum:DI (match_dup 0) (match_dup 1)))] + "operands[2] = pic_offset_table_rtx;") + +(define_split + [(match_operand 0 "some_small_symbolic_operand" "")] + "" + [(match_dup 0)] + "operands[0] = split_small_symbolic_operand (operands[0]);") + +;; Accepts any symbolic, not just global, since function calls that +;; don't go via bsr still use !literal in hopes of linker relaxation. +(define_insn "movdi_er_high_g" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "symbolic_operand" "") + (match_operand 3 "const_int_operand" "")] + UNSPEC_LITERAL))] + "TARGET_EXPLICIT_RELOCS" +{ + if (INTVAL (operands[3]) == 0) + return "ldq %0,%2(%1)\t\t!literal"; + else + return "ldq %0,%2(%1)\t\t!literal!%3"; +} + [(set_attr "type" "ldsym")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "global_symbolic_operand" ""))] + "TARGET_EXPLICIT_RELOCS && reload_completed" + [(set (match_dup 0) + (unspec:DI [(match_dup 2) + (match_dup 1) + (const_int 0)] UNSPEC_LITERAL))] + "operands[2] = pic_offset_table_rtx;") + +(define_insn "movdi_er_tlsgd" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "symbolic_operand" "") + (match_operand 3 "const_int_operand" "")] + UNSPEC_TLSGD))] + "HAVE_AS_TLS" +{ + if (INTVAL (operands[3]) == 0) + return "lda %0,%2(%1)\t\t!tlsgd"; + else + return "lda %0,%2(%1)\t\t!tlsgd!%3"; +}) + +(define_insn "movdi_er_tlsldm" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand 2 "const_int_operand" "")] + UNSPEC_TLSLDM))] + "HAVE_AS_TLS" +{ + if (INTVAL (operands[2]) == 0) + return "lda %0,%&(%1)\t\t!tlsldm"; + else + return "lda %0,%&(%1)\t\t!tlsldm!%2"; +}) + +(define_insn "*movdi_er_gotdtp" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "symbolic_operand" "")] + UNSPEC_DTPREL))] + "HAVE_AS_TLS" + "ldq %0,%2(%1)\t\t!gotdtprel" + [(set_attr "type" "ild") + (set_attr "usegp" "yes")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "gotdtp_symbolic_operand" ""))] + "HAVE_AS_TLS && reload_completed" + [(set (match_dup 0) + (unspec:DI [(match_dup 2) + (match_dup 1)] UNSPEC_DTPREL))] +{ + operands[1] = XVECEXP (XEXP (operands[1], 0), 0, 0); + operands[2] = pic_offset_table_rtx; +}) + +(define_insn "*movdi_er_gottp" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "symbolic_operand" "")] + UNSPEC_TPREL))] + "HAVE_AS_TLS" + "ldq %0,%2(%1)\t\t!gottprel" + [(set_attr "type" "ild") + (set_attr "usegp" "yes")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "gottp_symbolic_operand" ""))] + "HAVE_AS_TLS && reload_completed" + [(set (match_dup 0) + (unspec:DI [(match_dup 2) + (match_dup 1)] UNSPEC_TPREL))] +{ + operands[1] = XVECEXP (XEXP (operands[1], 0), 0, 0); + operands[2] = pic_offset_table_rtx; +}) + +(define_insn "*movdi_er_nofix" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,r,m,*f,*f,Q") + (match_operand:DI 1 "input_operand" "rJ,K,L,T,s,n,m,rJ,*fJ,Q,*f"))] + "TARGET_EXPLICIT_RELOCS && ! TARGET_FIX + && (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], DImode))" + "@ + mov %r1,%0 + lda %0,%1($31) + ldah %0,%h1($31) + # + # + # + ldq%A1 %0,%1 + stq%A0 %r1,%0 + fmov %R1,%0 + ldt %0,%1 + stt %R1,%0" + [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst") + (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*,*")]) + +;; The 'U' constraint matches symbolic operands on Unicos/Mk. Those should +;; have been split up by the rules above but we shouldn't reject the +;; possibility of them getting through. + +(define_insn "*movdi_nofix" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,r,m,*f,*f,Q") + (match_operand:DI 1 "input_operand" "rJ,K,L,U,s,n,m,rJ,*fJ,Q,*f"))] + "! TARGET_FIX + && (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], DImode))" + "@ + bis $31,%r1,%0 + lda %0,%1($31) + ldah %0,%h1($31) + laum %0,%t1($31)\;sll %0,32,%0\;lalm %0,%t1(%0)\;lal %0,%t1(%0) + lda %0,%1 + # + ldq%A1 %0,%1 + stq%A0 %r1,%0 + cpys %R1,%R1,%0 + ldt %0,%1 + stt %R1,%0" + [(set_attr "type" "ilog,iadd,iadd,ldsym,ldsym,multi,ild,ist,fcpys,fld,fst") + (set_attr "length" "*,*,*,16,*,*,*,*,*,*,*")]) + +(define_insn "*movdi_er_fix" + [(set (match_operand:DI 0 "nonimmediate_operand" + "=r,r,r,r,r,r,r, m, *f,*f, Q, r,*f") + (match_operand:DI 1 "input_operand" + "rJ,K,L,T,s,n,m,rJ,*fJ, Q,*f,*f, r"))] + "TARGET_EXPLICIT_RELOCS && TARGET_FIX + && (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], DImode))" + "@ + mov %r1,%0 + lda %0,%1($31) + ldah %0,%h1($31) + # + # + # + ldq%A1 %0,%1 + stq%A0 %r1,%0 + fmov %R1,%0 + ldt %0,%1 + stt %R1,%0 + ftoit %1,%0 + itoft %1,%0" + [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst,ftoi,itof") + (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*,*,*,*")]) + +(define_insn "*movdi_fix" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q,r,*f") + (match_operand:DI 1 "input_operand" "rJ,K,L,s,n,m,rJ,*fJ,Q,*f,*f,r"))] + "! TARGET_EXPLICIT_RELOCS && TARGET_FIX + && (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], DImode))" + "@ + bis $31,%r1,%0 + lda %0,%1($31) + ldah %0,%h1($31) + lda %0,%1 + # + ldq%A1 %0,%1 + stq%A0 %r1,%0 + cpys %R1,%R1,%0 + ldt %0,%1 + stt %R1,%0 + ftoit %1,%0 + itoft %1,%0" + [(set_attr "type" "ilog,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst,ftoi,itof")]) + +;; VMS needs to set up "vms_base_regno" for unwinding. This move +;; often appears dead to the life analysis code, at which point we +;; die for emitting dead prologue instructions. Force this live. + +(define_insn "force_movdi" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r")] + UNSPECV_FORCE_MOV))] + "" + "mov %1,%0" + [(set_attr "type" "ilog")]) + +;; We do three major things here: handle mem->mem, put 64-bit constants in +;; memory, and construct long 32-bit constants. + +(define_expand "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" +{ + if (alpha_expand_mov (DImode, operands)) + DONE; +}) + +;; Split a load of a large constant into the appropriate two-insn +;; sequence. + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "non_add_const_operand" ""))] + "" + [(const_int 0)] +{ + if (alpha_split_const_mov (DImode, operands)) + DONE; + else + FAIL; +}) + +;; We need to prevent reload from splitting TImode moves, because it +;; might decide to overwrite a pointer with the value it points to. +;; In that case we have to do the loads in the appropriate order so +;; that the pointer is not destroyed too early. + +(define_insn_and_split "*movti_internal" + [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o") + (match_operand:TI 1 "input_operand" "roJ,rJ"))] + "(register_operand (operands[0], TImode) + /* Prevent rematerialization of constants. */ + && ! CONSTANT_P (operands[1])) + || reg_or_0_operand (operands[1], TImode)" + "#" + "reload_completed" + [(set (match_dup 0) (match_dup 2)) + (set (match_dup 1) (match_dup 3))] +{ + alpha_split_tmode_pair (operands, TImode, true); +}) + +(define_expand "movti" + [(set (match_operand:TI 0 "nonimmediate_operand" "") + (match_operand:TI 1 "general_operand" ""))] + "" +{ + if (MEM_P (operands[0]) + && ! reg_or_0_operand (operands[1], TImode)) + operands[1] = force_reg (TImode, operands[1]); + + if (operands[1] == const0_rtx) + ; + /* We must put 64-bit constants in memory. We could keep the + 32-bit constants in TImode and rely on the splitter, but + this doesn't seem to be worth the pain. */ + else if (CONST_INT_P (operands[1]) + || GET_CODE (operands[1]) == CONST_DOUBLE) + { + rtx in[2], out[2], target; + + gcc_assert (can_create_pseudo_p ()); + + split_double (operands[1], &in[0], &in[1]); + + if (in[0] == const0_rtx) + out[0] = const0_rtx; + else + { + out[0] = gen_reg_rtx (DImode); + emit_insn (gen_movdi (out[0], in[0])); + } + + if (in[1] == const0_rtx) + out[1] = const0_rtx; + else + { + out[1] = gen_reg_rtx (DImode); + emit_insn (gen_movdi (out[1], in[1])); + } + + if (!REG_P (operands[0])) + target = gen_reg_rtx (TImode); + else + target = operands[0]; + + emit_insn (gen_movdi (operand_subword (target, 0, 0, TImode), out[0])); + emit_insn (gen_movdi (operand_subword (target, 1, 0, TImode), out[1])); + + if (target != operands[0]) + emit_insn (gen_rtx_SET (VOIDmode, operands[0], target)); + + DONE; + } +}) + +;; These are the partial-word cases. +;; +;; First we have the code to load an aligned word. Operand 0 is the register +;; in which to place the result. It's mode is QImode or HImode. Operand 1 +;; is an SImode MEM at the low-order byte of the proper word. Operand 2 is the +;; number of bits within the word that the value is. Operand 3 is an SImode +;; scratch register. If operand 0 is a hard register, operand 3 may be the +;; same register. It is allowed to conflict with operand 1 as well. + +(define_expand "aligned_loadqi" + [(set (match_operand:SI 3 "register_operand" "") + (match_operand:SI 1 "memory_operand" "")) + (set (match_operand:DI 0 "register_operand" "") + (zero_extract:DI (subreg:DI (match_dup 3) 0) + (const_int 8) + (match_operand:DI 2 "const_int_operand" "")))] + + "" + "") + +(define_expand "aligned_loadhi" + [(set (match_operand:SI 3 "register_operand" "") + (match_operand:SI 1 "memory_operand" "")) + (set (match_operand:DI 0 "register_operand" "") + (zero_extract:DI (subreg:DI (match_dup 3) 0) + (const_int 16) + (match_operand:DI 2 "const_int_operand" "")))] + + "" + "") + +;; Similar for unaligned loads, where we use the sequence from the +;; Alpha Architecture manual. We have to distinguish between little-endian +;; and big-endian systems as the sequences are different. +;; +;; 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" + [(use (match_operand:DI 0 "register_operand" "")) + (use (match_operand:DI 1 "address_operand" "")) + (use (match_operand:DI 2 "register_operand" "")) + (use (match_operand:DI 3 "register_operand" ""))] + "" +{ + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_loadqi_be (operands[0], operands[1], + operands[2], operands[3])); + else + emit_insn (gen_unaligned_loadqi_le (operands[0], operands[1], + operands[2], operands[3])); + DONE; +}) + +(define_expand "unaligned_loadqi_le" + [(set (match_operand:DI 2 "register_operand" "") + (mem:DI (and:DI (match_operand:DI 1 "address_operand" "") + (const_int -8)))) + (set (match_operand:DI 3 "register_operand" "") + (match_dup 1)) + (set (match_operand:DI 0 "register_operand" "") + (zero_extract:DI (match_dup 2) + (const_int 8) + (ashift:DI (match_dup 3) (const_int 3))))] + "! WORDS_BIG_ENDIAN" + "") + +(define_expand "unaligned_loadqi_be" + [(set (match_operand:DI 2 "register_operand" "") + (mem:DI (and:DI (match_operand:DI 1 "address_operand" "") + (const_int -8)))) + (set (match_operand:DI 3 "register_operand" "") + (match_dup 1)) + (set (match_operand:DI 0 "register_operand" "") + (zero_extract:DI (match_dup 2) + (const_int 8) + (minus:DI + (const_int 56) + (ashift:DI (match_dup 3) (const_int 3)))))] + "WORDS_BIG_ENDIAN" + "") + +(define_expand "unaligned_loadhi" + [(use (match_operand:DI 0 "register_operand" "")) + (use (match_operand:DI 1 "address_operand" "")) + (use (match_operand:DI 2 "register_operand" "")) + (use (match_operand:DI 3 "register_operand" ""))] + "" +{ + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_loadhi_be (operands[0], operands[1], + operands[2], operands[3])); + else + emit_insn (gen_unaligned_loadhi_le (operands[0], operands[1], + operands[2], operands[3])); + DONE; +}) + +(define_expand "unaligned_loadhi_le" + [(set (match_operand:DI 2 "register_operand" "") + (mem:DI (and:DI (match_operand:DI 1 "address_operand" "") + (const_int -8)))) + (set (match_operand:DI 3 "register_operand" "") + (match_dup 1)) + (set (match_operand:DI 0 "register_operand" "") + (zero_extract:DI (match_dup 2) + (const_int 16) + (ashift:DI (match_dup 3) (const_int 3))))] + "! WORDS_BIG_ENDIAN" + "") + +(define_expand "unaligned_loadhi_be" + [(set (match_operand:DI 2 "register_operand" "") + (mem:DI (and:DI (match_operand:DI 1 "address_operand" "") + (const_int -8)))) + (set (match_operand:DI 3 "register_operand" "") + (plus:DI (match_dup 1) (const_int 1))) + (set (match_operand:DI 0 "register_operand" "") + (zero_extract:DI (match_dup 2) + (const_int 16) + (minus:DI + (const_int 56) + (ashift:DI (match_dup 3) (const_int 3)))))] + "WORDS_BIG_ENDIAN" + "") + +;; 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 +;; the value should be placed. Operands 3 and 4 are SImode temporaries. + +(define_expand "aligned_store" + [(set (match_operand:SI 3 "register_operand" "") + (match_operand:SI 0 "memory_operand" "")) + (set (subreg:DI (match_dup 3) 0) + (and:DI (subreg:DI (match_dup 3) 0) (match_dup 5))) + (set (subreg:DI (match_operand:SI 4 "register_operand" "") 0) + (ashift:DI (zero_extend:DI (match_operand 1 "register_operand" "")) + (match_operand:DI 2 "const_int_operand" ""))) + (set (subreg:DI (match_dup 4) 0) + (ior:DI (subreg:DI (match_dup 4) 0) (subreg:DI (match_dup 3) 0))) + (set (match_dup 0) (match_dup 4))] + "" +{ + operands[5] = GEN_INT (~ (GET_MODE_MASK (GET_MODE (operands[1])) + << INTVAL (operands[2]))); +}) + +;; 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, +;; operand 2 can be that register. + +(define_expand "unaligned_storeqi" + [(use (match_operand:DI 0 "address_operand" "")) + (use (match_operand:QI 1 "register_operand" "")) + (use (match_operand:DI 2 "register_operand" "")) + (use (match_operand:DI 3 "register_operand" "")) + (use (match_operand:DI 4 "register_operand" ""))] + "" +{ + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_storeqi_be (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + else + emit_insn (gen_unaligned_storeqi_le (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + DONE; +}) + +(define_expand "unaligned_storeqi_le" + [(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 255) + (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:QI 1 "register_operand" "")) + (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))] + "! WORDS_BIG_ENDIAN" + "") + +(define_expand "unaligned_storeqi_be" + [(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 255) + (minus:DI (const_int 56) + (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:QI 1 "register_operand" "")) + (minus:DI (const_int 56) + (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))] + "WORDS_BIG_ENDIAN" + "") + +(define_expand "unaligned_storehi" + [(use (match_operand:DI 0 "address_operand" "")) + (use (match_operand:HI 1 "register_operand" "")) + (use (match_operand:DI 2 "register_operand" "")) + (use (match_operand:DI 3 "register_operand" "")) + (use (match_operand:DI 4 "register_operand" ""))] + "" +{ + if (WORDS_BIG_ENDIAN) + emit_insn (gen_unaligned_storehi_be (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + else + emit_insn (gen_unaligned_storehi_le (operands[0], operands[1], + operands[2], operands[3], + operands[4])); + DONE; +}) + +(define_expand "unaligned_storehi_le" + [(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 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 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))] + "! WORDS_BIG_ENDIAN" + "") + +(define_expand "unaligned_storehi_be" + [(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" "") + (plus:DI (match_dup 5) (const_int 1))) + (set (match_dup 3) + (and:DI (not:DI (ashift:DI + (const_int 65535) + (minus:DI (const_int 56) + (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" "")) + (minus:DI (const_int 56) + (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))] + "WORDS_BIG_ENDIAN" + "operands[5] = force_reg (DImode, operands[0]);") + +;; Here are the define_expand's for QI and HI moves that use the above +;; patterns. We have the normal sets, plus the ones that need scratch +;; registers for reload. + +(define_expand "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" +{ + if (TARGET_BWX + ? alpha_expand_mov (QImode, operands) + : alpha_expand_mov_nobwx (QImode, operands)) + DONE; +}) + +(define_expand "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" +{ + if (TARGET_BWX + ? alpha_expand_mov (HImode, operands) + : alpha_expand_mov_nobwx (HImode, operands)) + DONE; +}) + +;; We need to hook into the extra support that we have for HImode +;; reloads when BWX insns are not available. +(define_expand "movcqi" + [(set (match_operand:CQI 0 "nonimmediate_operand" "") + (match_operand:CQI 1 "general_operand" ""))] + "!TARGET_BWX" +{ + if (GET_CODE (operands[0]) == CONCAT || GET_CODE (operands[1]) == CONCAT) + ; + else if (!any_memory_operand (operands[0], CQImode)) + { + if (!any_memory_operand (operands[1], CQImode)) + { + emit_move_insn (gen_lowpart (HImode, operands[0]), + gen_lowpart (HImode, operands[1])); + DONE; + } + if (aligned_memory_operand (operands[1], CQImode)) + { + bool done; + do_aligned1: + operands[1] = gen_lowpart (HImode, operands[1]); + do_aligned2: + operands[0] = gen_lowpart (HImode, operands[0]); + done = alpha_expand_mov_nobwx (HImode, operands); + gcc_assert (done); + DONE; + } + } + else if (aligned_memory_operand (operands[0], CQImode)) + { + if (MEM_P (operands[1])) + { + rtx x = gen_reg_rtx (HImode); + emit_move_insn (gen_lowpart (CQImode, x), operands[1]); + operands[1] = x; + goto do_aligned2; + } + goto do_aligned1; + } + + gcc_assert (!reload_in_progress); + emit_move_complex_parts (operands[0], operands[1]); + DONE; +}) + +;; Here are the versions for reload. +;; +;; The aligned input case is recognized early in alpha_secondary_reload +;; in order to avoid allocating an unnecessary scratch register. +;; +;; Note that in the unaligned cases we know that the operand must not be +;; a pseudo-register because stack slots are always aligned references. + +(define_expand "reload_in<mode>" + [(parallel [(match_operand:RELOAD12 0 "register_operand" "=r") + (match_operand:RELOAD12 1 "any_memory_operand" "m") + (match_operand:TI 2 "register_operand" "=&r")])] + "!TARGET_BWX" +{ + rtx scratch, seq, addr; + unsigned regno = REGNO (operands[2]); + + /* 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. */ + if (regno == REGNO (operands[0])) + regno++; + scratch = gen_rtx_REG (DImode, regno); + + addr = get_unaligned_address (operands[1]); + operands[0] = gen_rtx_REG (DImode, REGNO (operands[0])); + seq = gen_unaligned_load<reloadmode> (operands[0], addr, + scratch, operands[0]); + alpha_set_memflags (seq, operands[1]); + + emit_insn (seq); + DONE; +}) + +(define_expand "reload_out<mode>" + [(parallel [(match_operand:RELOAD12 0 "any_memory_operand" "=m") + (match_operand:RELOAD12 1 "register_operand" "r") + (match_operand:TI 2 "register_operand" "=&r")])] + "! TARGET_BWX" +{ + unsigned regno = REGNO (operands[2]); + + if (<MODE>mode == CQImode) + { + operands[0] = gen_lowpart (HImode, operands[0]); + operands[1] = gen_lowpart (HImode, operands[1]); + } + + if (aligned_memory_operand (operands[0], <MODE>mode)) + { + emit_insn (gen_reload_out<reloadmode>_aligned + (operands[0], operands[1], + gen_rtx_REG (SImode, regno), + gen_rtx_REG (SImode, regno + 1))); + } + else + { + rtx addr = get_unaligned_address (operands[0]); + rtx scratch1 = gen_rtx_REG (DImode, regno); + rtx scratch2 = gen_rtx_REG (DImode, regno + 1); + rtx scratch3 = scratch1; + rtx seq; + + if (REG_P (addr)) + scratch1 = addr; + + seq = gen_unaligned_store<reloadmode> (addr, operands[1], scratch1, + scratch2, scratch3); + alpha_set_memflags (seq, operands[0]); + emit_insn (seq); + } + DONE; +}) + +;; Helpers for the above. The way reload is structured, we can't +;; always get a proper address for a stack slot during reload_foo +;; expansion, so we must delay our address manipulations until after. + +(define_insn_and_split "reload_in<mode>_aligned" + [(set (match_operand:I12MODE 0 "register_operand" "=r") + (match_operand:I12MODE 1 "memory_operand" "m"))] + "!TARGET_BWX && (reload_in_progress || reload_completed)" + "#" + "!TARGET_BWX && reload_completed" + [(const_int 0)] +{ + rtx aligned_mem, bitnum; + get_aligned_mem (operands[1], &aligned_mem, &bitnum); + emit_insn (gen_aligned_load<reloadmode> + (gen_lowpart (DImode, operands[0]), aligned_mem, bitnum, + gen_rtx_REG (SImode, REGNO (operands[0])))); + DONE; +}) + +(define_insn_and_split "reload_out<mode>_aligned" + [(set (match_operand:I12MODE 0 "memory_operand" "=m") + (match_operand:I12MODE 1 "register_operand" "r")) + (clobber (match_operand:SI 2 "register_operand" "=r")) + (clobber (match_operand:SI 3 "register_operand" "=r"))] + "!TARGET_BWX && (reload_in_progress || reload_completed)" + "#" + "!TARGET_BWX && reload_completed" + [(const_int 0)] +{ + rtx aligned_mem, bitnum; + get_aligned_mem (operands[0], &aligned_mem, &bitnum); + emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum, + operands[2], operands[3])); + DONE; +}) + +;; Vector operations + +(define_mode_iterator VEC [V8QI V4HI V2SI]) + +(define_expand "mov<mode>" + [(set (match_operand:VEC 0 "nonimmediate_operand" "") + (match_operand:VEC 1 "general_operand" ""))] + "" +{ + if (alpha_expand_mov (<MODE>mode, operands)) + DONE; +}) + +(define_split + [(set (match_operand:VEC 0 "register_operand" "") + (match_operand:VEC 1 "non_zero_const_operand" ""))] + "" + [(const_int 0)] +{ + if (alpha_split_const_mov (<MODE>mode, operands)) + DONE; + else + FAIL; +}) + + +(define_expand "movmisalign<mode>" + [(set (match_operand:VEC 0 "nonimmediate_operand" "") + (match_operand:VEC 1 "general_operand" ""))] + "" +{ + alpha_expand_movmisalign (<MODE>mode, operands); + DONE; +}) + +(define_insn "*mov<mode>_fix" + [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,r,m,*f,*f,m,r,*f") + (match_operand:VEC 1 "input_operand" "rW,i,m,rW,*fW,m,*f,*f,r"))] + "TARGET_FIX + && (register_operand (operands[0], <MODE>mode) + || reg_or_0_operand (operands[1], <MODE>mode))" + "@ + bis $31,%r1,%0 + # + ldq %0,%1 + stq %r1,%0 + cpys %R1,%R1,%0 + ldt %0,%1 + stt %R1,%0 + ftoit %1,%0 + itoft %1,%0" + [(set_attr "type" "ilog,multi,ild,ist,fcpys,fld,fst,ftoi,itof")]) + +(define_insn "*mov<mode>_nofix" + [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,r,m,*f,*f,m") + (match_operand:VEC 1 "input_operand" "rW,i,m,rW,*fW,m,*f"))] + "! TARGET_FIX + && (register_operand (operands[0], <MODE>mode) + || reg_or_0_operand (operands[1], <MODE>mode))" + "@ + bis $31,%r1,%0 + # + ldq %0,%1 + stq %r1,%0 + cpys %R1,%R1,%0 + ldt %0,%1 + stt %R1,%0" + [(set_attr "type" "ilog,multi,ild,ist,fcpys,fld,fst")]) + +(define_insn "uminv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=r") + (umin:V8QI (match_operand:V8QI 1 "reg_or_0_operand" "rW") + (match_operand:V8QI 2 "reg_or_0_operand" "rW")))] + "TARGET_MAX" + "minub8 %r1,%r2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "sminv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=r") + (smin:V8QI (match_operand:V8QI 1 "reg_or_0_operand" "rW") + (match_operand:V8QI 2 "reg_or_0_operand" "rW")))] + "TARGET_MAX" + "minsb8 %r1,%r2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "uminv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=r") + (umin:V4HI (match_operand:V4HI 1 "reg_or_0_operand" "rW") + (match_operand:V4HI 2 "reg_or_0_operand" "rW")))] + "TARGET_MAX" + "minuw4 %r1,%r2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "sminv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=r") + (smin:V4HI (match_operand:V4HI 1 "reg_or_0_operand" "rW") + (match_operand:V4HI 2 "reg_or_0_operand" "rW")))] + "TARGET_MAX" + "minsw4 %r1,%r2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "umaxv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=r") + (umax:V8QI (match_operand:V8QI 1 "reg_or_0_operand" "rW") + (match_operand:V8QI 2 "reg_or_0_operand" "rW")))] + "TARGET_MAX" + "maxub8 %r1,%r2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "smaxv8qi3" + [(set (match_operand:V8QI 0 "register_operand" "=r") + (smax:V8QI (match_operand:V8QI 1 "reg_or_0_operand" "rW") + (match_operand:V8QI 2 "reg_or_0_operand" "rW")))] + "TARGET_MAX" + "maxsb8 %r1,%r2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "umaxv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=r") + (umax:V4HI (match_operand:V4HI 1 "reg_or_0_operand" "rW") + (match_operand:V4HI 2 "reg_or_0_operand" "rW")))] + "TARGET_MAX" + "maxuw4 %r1,%r2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "smaxv4hi3" + [(set (match_operand:V4HI 0 "register_operand" "=r") + (smax:V4HI (match_operand:V4HI 1 "reg_or_0_operand" "rW") + (match_operand:V4HI 2 "reg_or_0_operand" "rW")))] + "TARGET_MAX" + "maxsw4 %r1,%r2,%0" + [(set_attr "type" "mvi")]) + +(define_insn "one_cmpl<mode>2" + [(set (match_operand:VEC 0 "register_operand" "=r") + (not:VEC (match_operand:VEC 1 "register_operand" "r")))] + "" + "ornot $31,%1,%0" + [(set_attr "type" "ilog")]) + +(define_insn "and<mode>3" + [(set (match_operand:VEC 0 "register_operand" "=r") + (and:VEC (match_operand:VEC 1 "register_operand" "r") + (match_operand:VEC 2 "register_operand" "r")))] + "" + "and %1,%2,%0" + [(set_attr "type" "ilog")]) + +(define_insn "*andnot<mode>3" + [(set (match_operand:VEC 0 "register_operand" "=r") + (and:VEC (not:VEC (match_operand:VEC 1 "register_operand" "r")) + (match_operand:VEC 2 "register_operand" "r")))] + "" + "bic %2,%1,%0" + [(set_attr "type" "ilog")]) + +(define_insn "ior<mode>3" + [(set (match_operand:VEC 0 "register_operand" "=r") + (ior:VEC (match_operand:VEC 1 "register_operand" "r") + (match_operand:VEC 2 "register_operand" "r")))] + "" + "bis %1,%2,%0" + [(set_attr "type" "ilog")]) + +(define_insn "*iornot<mode>3" + [(set (match_operand:VEC 0 "register_operand" "=r") + (ior:VEC (not:DI (match_operand:VEC 1 "register_operand" "r")) + (match_operand:VEC 2 "register_operand" "r")))] + "" + "ornot %2,%1,%0" + [(set_attr "type" "ilog")]) + +(define_insn "xor<mode>3" + [(set (match_operand:VEC 0 "register_operand" "=r") + (xor:VEC (match_operand:VEC 1 "register_operand" "r") + (match_operand:VEC 2 "register_operand" "r")))] + "" + "xor %1,%2,%0" + [(set_attr "type" "ilog")]) + +(define_insn "*xornot<mode>3" + [(set (match_operand:VEC 0 "register_operand" "=r") + (not:VEC (xor:VEC (match_operand:VEC 1 "register_operand" "r") + (match_operand:VEC 2 "register_operand" "r"))))] + "" + "eqv %1,%2,%0" + [(set_attr "type" "ilog")]) + +(define_expand "vec_shl_<mode>" + [(set (match_operand:VEC 0 "register_operand" "") + (ashift:DI (match_operand:VEC 1 "register_operand" "") + (match_operand:DI 2 "reg_or_6bit_operand" "")))] + "" +{ + operands[0] = gen_lowpart (DImode, operands[0]); + operands[1] = gen_lowpart (DImode, operands[1]); +}) + +(define_expand "vec_shr_<mode>" + [(set (match_operand:VEC 0 "register_operand" "") + (lshiftrt:DI (match_operand:VEC 1 "register_operand" "") + (match_operand:DI 2 "reg_or_6bit_operand" "")))] + "" +{ + operands[0] = gen_lowpart (DImode, operands[0]); + operands[1] = gen_lowpart (DImode, operands[1]); +}) + +;; 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" "")))] + "" +{ + int ofs; + + /* 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 (!MEM_P (operands[1])) + FAIL; + + /* The bit number is relative to the mode of operand 1 which is + usually QImode (this might actually be a bug in expmed.c). Note + that the bit number is negative in big-endian mode in this case. + We have to convert that to the offset. */ + if (WORDS_BIG_ENDIAN) + ofs = GET_MODE_BITSIZE (GET_MODE (operands[1])) + - INTVAL (operands[2]) - INTVAL (operands[3]); + else + ofs = INTVAL (operands[3]); + + ofs = ofs / 8; + + alpha_expand_unaligned_load (operands[0], operands[1], + INTVAL (operands[2]) / 8, + ofs, 1); + DONE; +}) + +(define_expand "extzv" + [(set (match_operand:DI 0 "register_operand" "") + (zero_extract:DI (match_operand:DI 1 "nonimmediate_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 (MEM_P (operands[1])) + { + int ofs; + + /* Fail 8-bit fields, falling back on a simple byte load. */ + if (INTVAL (operands[2]) == 8) + FAIL; + + /* The bit number is relative to the mode of operand 1 which is + usually QImode (this might actually be a bug in expmed.c). Note + that the bit number is negative in big-endian mode in this case. + We have to convert that to the offset. */ + if (WORDS_BIG_ENDIAN) + ofs = GET_MODE_BITSIZE (GET_MODE (operands[1])) + - INTVAL (operands[2]) - INTVAL (operands[3]); + else + ofs = INTVAL (operands[3]); + + ofs = ofs / 8; + + alpha_expand_unaligned_load (operands[0], operands[1], + INTVAL (operands[2]) / 8, + ofs, 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" ""))] + "" +{ + int ofs; + + /* 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 (!MEM_P (operands[0])) + FAIL; + + /* The bit number is relative to the mode of operand 1 which is + usually QImode (this might actually be a bug in expmed.c). Note + that the bit number is negative in big-endian mode in this case. + We have to convert that to the offset. */ + if (WORDS_BIG_ENDIAN) + ofs = GET_MODE_BITSIZE (GET_MODE (operands[0])) + - INTVAL (operands[1]) - INTVAL (operands[2]); + else + ofs = INTVAL (operands[2]); + + ofs = ofs / 8; + + alpha_expand_unaligned_store (operands[0], operands[3], + INTVAL (operands[1]) / 8, ofs); + 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 "movmemqi" + [(parallel [(set (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_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 "movmemdi" + [(parallel [(set (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_operand" "")) + (use (match_operand:DI 2 "immediate_operand" "")) + (use (match_operand:DI 3 "immediate_operand" "")) + (use (match_dup 4)) + (clobber (reg:DI 25)) + (clobber (reg:DI 16)) + (clobber (reg:DI 17)) + (clobber (reg:DI 18)) + (clobber (reg:DI 19)) + (clobber (reg:DI 20)) + (clobber (reg:DI 26)) + (clobber (reg:DI 27))])] + "TARGET_ABI_OPEN_VMS" +{ + operands[4] = alpha_need_linkage ("OTS$MOVE", 0); +}) + +(define_insn "*movmemdi_1" + [(set (match_operand:BLK 0 "memory_operand" "=m,=m") + (match_operand:BLK 1 "memory_operand" "m,m")) + (use (match_operand:DI 2 "nonmemory_operand" "r,i")) + (use (match_operand:DI 3 "immediate_operand" "")) + (use (match_operand:DI 4 "call_operand" "i,i")) + (clobber (reg:DI 25)) + (clobber (reg:DI 16)) + (clobber (reg:DI 17)) + (clobber (reg:DI 18)) + (clobber (reg:DI 19)) + (clobber (reg:DI 20)) + (clobber (reg:DI 26)) + (clobber (reg:DI 27))] + "TARGET_ABI_OPEN_VMS" +{ + operands [5] = alpha_use_linkage (operands [4], cfun->decl, 0, 1); + switch (which_alternative) + { + case 0: + return "lda $16,%0\;bis $31,%2,$17\;lda $18,%1\;ldq $26,%5\;lda $25,3($31)\;jsr $26,%4\;ldq $27,0($29)"; + case 1: + return "lda $16,%0\;lda $17,%2($31)\;lda $18,%1\;ldq $26,%5\;lda $25,3($31)\;jsr $26,%4\;ldq $27,0($29)"; + default: + gcc_unreachable (); + } +} + [(set_attr "type" "multi") + (set_attr "length" "28")]) + +(define_expand "setmemqi" + [(parallel [(set (match_operand:BLK 0 "memory_operand" "") + (match_operand 2 "const_int_operand" "")) + (use (match_operand:DI 1 "immediate_operand" "")) + (use (match_operand:DI 3 "immediate_operand" ""))])] + "" +{ + /* If value to set is not zero, use the library routine. */ + if (operands[2] != const0_rtx) + FAIL; + + if (alpha_expand_block_clear (operands)) + DONE; + else + FAIL; +}) + +(define_expand "setmemdi" + [(parallel [(set (match_operand:BLK 0 "memory_operand" "") + (match_operand 2 "const_int_operand" "")) + (use (match_operand:DI 1 "immediate_operand" "")) + (use (match_operand:DI 3 "immediate_operand" "")) + (use (match_dup 4)) + (clobber (reg:DI 25)) + (clobber (reg:DI 16)) + (clobber (reg:DI 17)) + (clobber (reg:DI 26)) + (clobber (reg:DI 27))])] + "TARGET_ABI_OPEN_VMS" +{ + /* If value to set is not zero, use the library routine. */ + if (operands[2] != const0_rtx) + FAIL; + + operands[4] = alpha_need_linkage ("OTS$ZERO", 0); +}) + +(define_insn "*clrmemdi_1" + [(set (match_operand:BLK 0 "memory_operand" "=m,=m") + (const_int 0)) + (use (match_operand:DI 1 "nonmemory_operand" "r,i")) + (use (match_operand:DI 2 "immediate_operand" "")) + (use (match_operand:DI 3 "call_operand" "i,i")) + (clobber (reg:DI 25)) + (clobber (reg:DI 16)) + (clobber (reg:DI 17)) + (clobber (reg:DI 26)) + (clobber (reg:DI 27))] + "TARGET_ABI_OPEN_VMS" +{ + operands [4] = alpha_use_linkage (operands [3], cfun->decl, 0, 1); + switch (which_alternative) + { + case 0: + return "lda $16,%0\;bis $31,%1,$17\;ldq $26,%4\;lda $25,2($31)\;jsr $26,%3\;ldq $27,0($29)"; + case 1: + return "lda $16,%0\;lda $17,%1($31)\;ldq $26,%4\;lda $25,2($31)\;jsr $26,%3\;ldq $27,0($29)"; + default: + gcc_unreachable (); + } +} + [(set_attr "type" "multi") + (set_attr "length" "24")]) + + +;; 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]))); + MEM_VOLATILE_P (operands[1]) = 1; + + operands[0] = const0_rtx; +}) + +;; This is how we allocate stack space. If we are allocating a +;; constant amount of space and we know it is less than 4096 +;; bytes, we need do nothing. +;; +;; If it is more than 4096 bytes, we need to probe the stack +;; periodically. +(define_expand "allocate_stack" + [(set (reg:DI 30) + (plus:DI (reg:DI 30) + (match_operand:DI 1 "reg_or_cint_operand" ""))) + (set (match_operand:DI 0 "register_operand" "=r") + (match_dup 2))] + "" +{ + if (CONST_INT_P (operands[1]) + && INTVAL (operands[1]) < 32768) + { + 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. */ + + int probed = 4096; + + emit_insn (gen_probe_stack (GEN_INT (- probed))); + while (probed + 8192 < INTVAL (operands[1])) + emit_insn (gen_probe_stack (GEN_INT (- (probed += 8192)))); + + if (probed + 4096 < INTVAL (operands[1])) + emit_insn (gen_probe_stack (GEN_INT (- INTVAL(operands[1])))); + } + + operands[1] = GEN_INT (- INTVAL (operands[1])); + operands[2] = virtual_stack_dynamic_rtx; + } + else + { + rtx out_label = 0; + rtx loop_label = gen_label_rtx (); + rtx want = gen_reg_rtx (Pmode); + rtx tmp = gen_reg_rtx (Pmode); + rtx memref, test; + + emit_insn (gen_subdi3 (want, stack_pointer_rtx, + force_reg (Pmode, operands[1]))); + + if (!CONST_INT_P (operands[1])) + { + rtx limit = GEN_INT (4096); + out_label = gen_label_rtx (); + test = gen_rtx_LTU (VOIDmode, operands[1], limit); + emit_jump_insn + (gen_cbranchdi4 (test, operands[1], limit, out_label)); + } + + emit_insn (gen_adddi3 (tmp, stack_pointer_rtx, GEN_INT (-4096))); + emit_label (loop_label); + 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))); + test = gen_rtx_GTU (VOIDmode, tmp, want); + emit_jump_insn (gen_cbranchdi4 (test, tmp, want, loop_label)); + + memref = gen_rtx_MEM (DImode, want); + MEM_VOLATILE_P (memref) = 1; + emit_move_insn (memref, const0_rtx); + + if (out_label) + 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:DI 0 "register_operand" "r") + (match_operand:DI 1 "register_operand" "r")] + UNSPECV_PSPL)] + "" +{ + operands[2] = gen_label_rtx (); + (*targetm.asm_out.internal_label) (asm_out_file, "L", + CODE_LABEL_NUMBER (operands[2])); + + return "stq $31,-8192(%1)\;subq %0,1,%0\;lda %1,-8192(%1)\;bne %0,%l2"; +} + [(set_attr "length" "16") + (set_attr "type" "multi")]) + +(define_expand "prologue" + [(clobber (const_int 0))] + "" +{ + alpha_expand_prologue (); + DONE; +}) + +;; These take care of emitting the ldgp insn in the prologue. This will be +;; an lda/ldah pair and we want to align them properly. So we have two +;; unspec_volatile insns, the first of which emits the ldgp assembler macro +;; and the second of which emits nothing. However, both are marked as type +;; IADD (the default) so the alignment code in alpha.c does the right thing +;; with them. + +(define_expand "prologue_ldgp" + [(set (match_dup 0) + (unspec_volatile:DI [(match_dup 1) (match_dup 2)] UNSPECV_LDGP1)) + (set (match_dup 0) + (unspec_volatile:DI [(match_dup 0) (match_dup 2)] UNSPECV_PLDGP2))] + "" +{ + operands[0] = pic_offset_table_rtx; + operands[1] = gen_rtx_REG (Pmode, 27); + operands[2] = (TARGET_EXPLICIT_RELOCS + ? GEN_INT (alpha_next_sequence_number++) + : const0_rtx); +}) + +(define_insn "*ldgp_er_1" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand 2 "const_int_operand" "")] + UNSPECV_LDGP1))] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "ldah %0,0(%1)\t\t!gpdisp!%2" + [(set_attr "cannot_copy" "true")]) + +(define_insn "*ldgp_er_2" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand 2 "const_int_operand" "")] + UNSPEC_LDGP2))] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "lda %0,0(%1)\t\t!gpdisp!%2" + [(set_attr "cannot_copy" "true")]) + +(define_insn "*prologue_ldgp_er_2" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand 2 "const_int_operand" "")] + UNSPECV_PLDGP2))] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "lda %0,0(%1)\t\t!gpdisp!%2\n$%~..ng:" + [(set_attr "cannot_copy" "true")]) + +(define_insn "*prologue_ldgp_1" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand 2 "const_int_operand" "")] + UNSPECV_LDGP1))] + "" + "ldgp %0,0(%1)\n$%~..ng:" + [(set_attr "cannot_copy" "true")]) + +(define_insn "*prologue_ldgp_2" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec_volatile:DI [(match_operand:DI 1 "register_operand" "r") + (match_operand 2 "const_int_operand" "")] + UNSPECV_PLDGP2))] + "" + "") + +;; The _mcount profiling hook has special calling conventions, and +;; does not clobber all the registers that a normal call would. So +;; hide the fact this is a call at all. + +(define_insn "prologue_mcount" + [(unspec_volatile [(const_int 0)] UNSPECV_MCOUNT)] + "" +{ + if (TARGET_EXPLICIT_RELOCS) + /* Note that we cannot use a lituse_jsr reloc, since _mcount + cannot be called via the PLT. */ + return "ldq $28,_mcount($29)\t\t!literal\;jsr $28,($28),_mcount"; + else + return "lda $28,_mcount\;jsr $28,($28),_mcount"; +} + [(set_attr "type" "multi") + (set_attr "length" "8")]) + +(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 $31,%1,%0") + +(define_expand "epilogue" + [(return)] + "" +{ + alpha_expand_epilogue (); +}) + +(define_expand "sibcall_epilogue" + [(return)] + "TARGET_ABI_OSF" +{ + alpha_expand_epilogue (); + DONE; +}) + +(define_expand "builtin_longjmp" + [(use (match_operand:DI 0 "register_operand" "r"))] + "TARGET_ABI_OSF" +{ + /* 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); + emit_use (hard_frame_pointer_rtx); + emit_use (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_jump_insn (gen_builtin_longjmp_internal (pv)); + emit_barrier (); + DONE; +}) + +;; This is effectively a copy of indirect_jump, but constrained such +;; that register renaming cannot foil our cunning plan with $27. +(define_insn "builtin_longjmp_internal" + [(set (pc) + (unspec_volatile [(match_operand:DI 0 "register_operand" "c")] + UNSPECV_LONGJMP))] + "" + "jmp $31,(%0),0" + [(set_attr "type" "ibr")]) + +(define_expand "builtin_setjmp_receiver" + [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)] + "TARGET_ABI_OSF" + "") + +(define_insn_and_split "*builtin_setjmp_receiver_1" + [(unspec_volatile [(match_operand 0 "" "")] UNSPECV_SETJMPR)] + "TARGET_ABI_OSF" +{ + if (TARGET_EXPLICIT_RELOCS) + return "#"; + else + return "br $27,$LSJ%=\n$LSJ%=:\;ldgp $29,0($27)"; +} + "&& TARGET_EXPLICIT_RELOCS && reload_completed" + [(set (match_dup 1) + (unspec_volatile:DI [(match_dup 2) (match_dup 3)] UNSPECV_LDGP1)) + (set (match_dup 1) + (unspec:DI [(match_dup 1) (match_dup 3)] UNSPEC_LDGP2))] +{ + if (prev_nonnote_insn (curr_insn) != XEXP (operands[0], 0)) + emit_insn (gen_rtx_UNSPEC_VOLATILE (VOIDmode, gen_rtvec (1, operands[0]), + UNSPECV_SETJMPR_ER)); + operands[1] = pic_offset_table_rtx; + operands[2] = gen_rtx_REG (Pmode, 27); + operands[3] = GEN_INT (alpha_next_sequence_number++); +} + [(set_attr "length" "12") + (set_attr "type" "multi")]) + +(define_insn "*builtin_setjmp_receiver_er_sl_1" + [(unspec_volatile [(match_operand 0 "" "")] UNSPECV_SETJMPR_ER)] + "TARGET_ABI_OSF && TARGET_EXPLICIT_RELOCS && TARGET_AS_CAN_SUBTRACT_LABELS" + "lda $27,$LSJ%=-%l0($27)\n$LSJ%=:") + +(define_insn "*builtin_setjmp_receiver_er_1" + [(unspec_volatile [(match_operand 0 "" "")] UNSPECV_SETJMPR_ER)] + "TARGET_ABI_OSF && TARGET_EXPLICIT_RELOCS" + "br $27,$LSJ%=\n$LSJ%=:" + [(set_attr "type" "ibr")]) + +;; When flag_reorder_blocks_and_partition is in effect, compiler puts +;; exception landing pads in a cold section. To prevent inter-section offset +;; calculation, a jump to original landing pad is emitted in the place of the +;; original landing pad. Since landing pad is moved, RA-relative GP +;; calculation in the prologue of landing pad breaks. To solve this problem, +;; we use alternative GP load approach, as in the case of TARGET_LD_BUGGY_LDGP. + +(define_expand "exception_receiver" + [(unspec_volatile [(match_dup 0)] UNSPECV_EHR)] + "TARGET_ABI_OSF" +{ + if (TARGET_LD_BUGGY_LDGP || flag_reorder_blocks_and_partition) + operands[0] = alpha_gp_save_rtx (); + else + operands[0] = const0_rtx; +}) + +(define_insn "*exception_receiver_2" + [(unspec_volatile [(match_operand:DI 0 "memory_operand" "m")] UNSPECV_EHR)] + "TARGET_ABI_OSF + && (TARGET_LD_BUGGY_LDGP || flag_reorder_blocks_and_partition)" + "ldq $29,%0" + [(set_attr "type" "ild")]) + +(define_insn_and_split "*exception_receiver_1" + [(unspec_volatile [(const_int 0)] UNSPECV_EHR)] + "TARGET_ABI_OSF" +{ + if (TARGET_EXPLICIT_RELOCS) + return "ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*"; + else + return "ldgp $29,0($26)"; +} + "&& TARGET_EXPLICIT_RELOCS && reload_completed" + [(set (match_dup 0) + (unspec_volatile:DI [(match_dup 1) (match_dup 2)] UNSPECV_LDGP1)) + (set (match_dup 0) + (unspec:DI [(match_dup 0) (match_dup 2)] UNSPEC_LDGP2))] +{ + operands[0] = pic_offset_table_rtx; + operands[1] = gen_rtx_REG (Pmode, 26); + operands[2] = GEN_INT (alpha_next_sequence_number++); +} + [(set_attr "length" "8") + (set_attr "type" "multi")]) + +(define_expand "nonlocal_goto_receiver" + [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE) + (set (reg:DI 27) (mem:DI (reg:DI 29))) + (unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE) + (use (reg:DI 27))] + "TARGET_ABI_OPEN_VMS" + "") + +(define_insn "arg_home" + [(unspec [(const_int 0)] UNSPEC_ARG_HOME) + (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_ABI_OPEN_VMS" + "lda $0,OTS$HOME_ARGS\;ldq $0,8($0)\;jsr $0,OTS$HOME_ARGS" + [(set_attr "length" "16") + (set_attr "type" "multi")]) + +;; Load the CIW into r2 for calling __T3E_MISMATCH + +(define_expand "umk_mismatch_args" + [(set (match_dup 1) (mem:DI (plus:DI (reg:DI 15) (const_int -16)))) + (set (match_dup 2) (mem:DI (plus:DI (match_dup 1) (const_int -32)))) + (set (reg:DI 1) (match_operand:DI 0 "const_int_operand" "")) + (set (match_dup 3) (plus:DI (mult:DI (reg:DI 25) + (const_int 8)) + (match_dup 2))) + (set (reg:DI 2) (mem:DI (match_dup 3)))] + "TARGET_ABI_UNICOSMK" +{ + operands[1] = gen_reg_rtx (DImode); + operands[2] = gen_reg_rtx (DImode); + operands[3] = gen_reg_rtx (DImode); +}) + +(define_insn "arg_home_umk" + [(unspec [(const_int 0)] UNSPEC_ARG_HOME) + (use (reg:DI 1)) + (use (reg:DI 2)) + (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))) + (parallel [ + (clobber (reg:DI 22)) + (clobber (reg:DI 23)) + (clobber (reg:DI 24)) + (clobber (reg:DI 0)) + (clobber (reg:DI 1)) + (clobber (reg:DI 2)) + (clobber (reg:DI 3)) + (clobber (reg:DI 4)) + (clobber (reg:DI 5)) + (clobber (reg:DI 6)) + (clobber (reg:DI 7)) + (clobber (reg:DI 8))])] + "TARGET_ABI_UNICOSMK" + "laum $4,__T3E_MISMATCH($31)\;sll $4,32,$4\;lalm $4,__T3E_MISMATCH($4)\;lal $4,__T3E_MISMATCH($4)\;jsr $3,($4)" + [(set_attr "length" "16") + (set_attr "type" "multi")]) + +;; Prefetch data. +;; +;; On EV4, these instructions are nops -- no load occurs. +;; +;; On EV5, these instructions act as a normal load, and thus can trap +;; if the address is invalid. The OS may (or may not) handle this in +;; the entMM fault handler and suppress the fault. If so, then this +;; has the effect of a read prefetch instruction. +;; +;; On EV6, these become official prefetch instructions. + +(define_insn "prefetch" + [(prefetch (match_operand:DI 0 "address_operand" "p") + (match_operand:DI 1 "const_int_operand" "n") + (match_operand:DI 2 "const_int_operand" "n"))] + "TARGET_FIXUP_EV5_PREFETCH || alpha_cpu == PROCESSOR_EV6" +{ + /* Interpret "no temporal locality" as this data should be evicted once + it is used. The "evict next" alternatives load the data into the cache + and leave the LRU eviction counter pointing to that block. */ + static const char * const alt[2][2] = { + { + "ldq $31,%a0", /* read, evict next */ + "ldl $31,%a0", /* read, evict last */ + }, + { + "ldt $f31,%a0", /* write, evict next */ + "lds $f31,%a0", /* write, evict last */ + } + }; + + bool write = INTVAL (operands[1]) != 0; + bool lru = INTVAL (operands[2]) != 0; + + return alt[write][lru]; +} + [(set_attr "type" "ild")]) + +;; Close the trap shadow of preceding instructions. This is generated +;; by alpha_reorg. + +(define_insn "trapb" + [(unspec_volatile [(const_int 0)] UNSPECV_TRAPB)] + "" + "trapb" + [(set_attr "type" "misc")]) + +;; No-op instructions used by machine-dependent reorg to preserve +;; alignment for instruction issue. +;; The Unicos/Mk assembler does not support these opcodes. + +(define_insn "nop" + [(const_int 0)] + "" + "bis $31,$31,$31" + [(set_attr "type" "ilog")]) + +(define_insn "fnop" + [(const_int 1)] + "TARGET_FP" + "cpys $f31,$f31,$f31" + [(set_attr "type" "fcpys")]) + +(define_insn "unop" + [(const_int 2)] + "" + "ldq_u $31,0($30)") + +;; On Unicos/Mk we use a macro for aligning code. + +(define_insn "realign" + [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] + UNSPECV_REALIGN)] + "" +{ + if (TARGET_ABI_UNICOSMK) + return "gcc@code@align %0"; + else + return ".align %0 #realign"; +}) + +;; Instructions to be emitted from __builtins. + +(define_insn "builtin_cmpbge" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "reg_or_0_operand" "rJ") + (match_operand:DI 2 "reg_or_8bit_operand" "rI")] + UNSPEC_CMPBGE))] + "" + "cmpbge %r1,%2,%0" + ;; The EV6 data sheets list this as ILOG. OTOH, EV6 doesn't + ;; actually differentiate between ILOG and ICMP in the schedule. + [(set_attr "type" "icmp")]) + +(define_expand "builtin_extbl" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx, rtx); + if (WORDS_BIG_ENDIAN) + gen = gen_extxl_be; + else + gen = gen_extxl_le; + emit_insn ((*gen) (operands[0], operands[1], GEN_INT (8), operands[2])); + DONE; +}) + +(define_expand "builtin_extwl" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx, rtx); + if (WORDS_BIG_ENDIAN) + gen = gen_extxl_be; + else + gen = gen_extxl_le; + emit_insn ((*gen) (operands[0], operands[1], GEN_INT (16), operands[2])); + DONE; +}) + +(define_expand "builtin_extll" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx, rtx); + if (WORDS_BIG_ENDIAN) + gen = gen_extxl_be; + else + gen = gen_extxl_le; + emit_insn ((*gen) (operands[0], operands[1], GEN_INT (32), operands[2])); + DONE; +}) + +(define_expand "builtin_extql" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx, rtx); + if (WORDS_BIG_ENDIAN) + gen = gen_extxl_be; + else + gen = gen_extxl_le; + emit_insn ((*gen) (operands[0], operands[1], GEN_INT (64), operands[2])); + DONE; +}) + +(define_expand "builtin_extwh" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx); + if (WORDS_BIG_ENDIAN) + gen = gen_extwh_be; + else + gen = gen_extwh_le; + emit_insn ((*gen) (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_expand "builtin_extlh" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx); + if (WORDS_BIG_ENDIAN) + gen = gen_extlh_be; + else + gen = gen_extlh_le; + emit_insn ((*gen) (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_expand "builtin_extqh" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx); + if (WORDS_BIG_ENDIAN) + gen = gen_extqh_be; + else + gen = gen_extqh_le; + emit_insn ((*gen) (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_expand "builtin_insbl" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx); + if (WORDS_BIG_ENDIAN) + gen = gen_insbl_be; + else + gen = gen_insbl_le; + operands[1] = gen_lowpart (QImode, operands[1]); + emit_insn ((*gen) (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_expand "builtin_inswl" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx); + if (WORDS_BIG_ENDIAN) + gen = gen_inswl_be; + else + gen = gen_inswl_le; + operands[1] = gen_lowpart (HImode, operands[1]); + emit_insn ((*gen) (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_expand "builtin_insll" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx); + if (WORDS_BIG_ENDIAN) + gen = gen_insll_be; + else + gen = gen_insll_le; + operands[1] = gen_lowpart (SImode, operands[1]); + emit_insn ((*gen) (operands[0], operands[1], operands[2])); + emit_insn ((*gen) (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_expand "builtin_insql" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx); + if (WORDS_BIG_ENDIAN) + gen = gen_insql_be; + else + gen = gen_insql_le; + emit_insn ((*gen) (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_expand "builtin_inswh" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + emit_insn (gen_insxh (operands[0], operands[1], GEN_INT (16), operands[2])); + DONE; +}) + +(define_expand "builtin_inslh" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + emit_insn (gen_insxh (operands[0], operands[1], GEN_INT (32), operands[2])); + DONE; +}) + +(define_expand "builtin_insqh" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + emit_insn (gen_insxh (operands[0], operands[1], GEN_INT (64), operands[2])); + DONE; +}) + +(define_expand "builtin_mskbl" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx, rtx); + rtx mask; + if (WORDS_BIG_ENDIAN) + gen = gen_mskxl_be; + else + gen = gen_mskxl_le; + mask = GEN_INT (0xff); + emit_insn ((*gen) (operands[0], operands[1], mask, operands[2])); + DONE; +}) + +(define_expand "builtin_mskwl" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx, rtx); + rtx mask; + if (WORDS_BIG_ENDIAN) + gen = gen_mskxl_be; + else + gen = gen_mskxl_le; + mask = GEN_INT (0xffff); + emit_insn ((*gen) (operands[0], operands[1], mask, operands[2])); + DONE; +}) + +(define_expand "builtin_mskll" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx, rtx); + rtx mask; + if (WORDS_BIG_ENDIAN) + gen = gen_mskxl_be; + else + gen = gen_mskxl_le; + mask = immed_double_const (0xffffffff, 0, DImode); + emit_insn ((*gen) (operands[0], operands[1], mask, operands[2])); + DONE; +}) + +(define_expand "builtin_mskql" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + rtx (*gen) (rtx, rtx, rtx, rtx); + rtx mask; + if (WORDS_BIG_ENDIAN) + gen = gen_mskxl_be; + else + gen = gen_mskxl_le; + mask = constm1_rtx; + emit_insn ((*gen) (operands[0], operands[1], mask, operands[2])); + DONE; +}) + +(define_expand "builtin_mskwh" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + emit_insn (gen_mskxh (operands[0], operands[1], GEN_INT (16), operands[2])); + DONE; +}) + +(define_expand "builtin_msklh" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + emit_insn (gen_mskxh (operands[0], operands[1], GEN_INT (32), operands[2])); + DONE; +}) + +(define_expand "builtin_mskqh" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "reg_or_8bit_operand" "")] + "" +{ + emit_insn (gen_mskxh (operands[0], operands[1], GEN_INT (64), operands[2])); + DONE; +}) + +(define_expand "builtin_zap" + [(set (match_operand:DI 0 "register_operand" "") + (and:DI (unspec:DI + [(match_operand:DI 2 "reg_or_cint_operand" "")] + UNSPEC_ZAP) + (match_operand:DI 1 "reg_or_cint_operand" "")))] + "" +{ + if (CONST_INT_P (operands[2])) + { + rtx mask = alpha_expand_zap_mask (INTVAL (operands[2])); + + if (mask == const0_rtx) + { + emit_move_insn (operands[0], const0_rtx); + DONE; + } + if (mask == constm1_rtx) + { + emit_move_insn (operands[0], operands[1]); + DONE; + } + + operands[1] = force_reg (DImode, operands[1]); + emit_insn (gen_anddi3 (operands[0], operands[1], mask)); + DONE; + } + + operands[1] = force_reg (DImode, operands[1]); + operands[2] = gen_lowpart (QImode, operands[2]); +}) + +(define_insn "*builtin_zap_1" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r") + (and:DI (unspec:DI + [(match_operand:QI 2 "reg_or_cint_operand" "n,n,r,r")] + UNSPEC_ZAP) + (match_operand:DI 1 "reg_or_cint_operand" "n,r,J,r")))] + "" + "@ + # + # + bis $31,$31,%0 + zap %r1,%2,%0" + [(set_attr "type" "shift,shift,ilog,shift")]) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (and:DI (unspec:DI + [(match_operand:QI 2 "const_int_operand" "")] + UNSPEC_ZAP) + (match_operand:DI 1 "const_int_operand" "")))] + "" + [(const_int 0)] +{ + rtx mask = alpha_expand_zap_mask (INTVAL (operands[2])); + if (HOST_BITS_PER_WIDE_INT >= 64 || CONST_INT_P (mask)) + operands[1] = gen_int_mode (INTVAL (operands[1]) & INTVAL (mask), DImode); + else + { + HOST_WIDE_INT c_lo = INTVAL (operands[1]); + HOST_WIDE_INT c_hi = (c_lo < 0 ? -1 : 0); + operands[1] = immed_double_const (c_lo & CONST_DOUBLE_LOW (mask), + c_hi & CONST_DOUBLE_HIGH (mask), + DImode); + } + emit_move_insn (operands[0], operands[1]); + DONE; +}) + +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (and:DI (unspec:DI + [(match_operand:QI 2 "const_int_operand" "")] + UNSPEC_ZAP) + (match_operand:DI 1 "register_operand" "")))] + "" + [(set (match_dup 0) + (and:DI (match_dup 1) (match_dup 2)))] +{ + operands[2] = alpha_expand_zap_mask (INTVAL (operands[2])); + if (operands[2] == const0_rtx) + { + emit_move_insn (operands[0], const0_rtx); + DONE; + } + if (operands[2] == constm1_rtx) + { + emit_move_insn (operands[0], operands[1]); + DONE; + } +}) + +(define_expand "builtin_zapnot" + [(set (match_operand:DI 0 "register_operand" "") + (and:DI (unspec:DI + [(not:QI (match_operand:DI 2 "reg_or_cint_operand" ""))] + UNSPEC_ZAP) + (match_operand:DI 1 "reg_or_cint_operand" "")))] + "" +{ + if (CONST_INT_P (operands[2])) + { + rtx mask = alpha_expand_zap_mask (~ INTVAL (operands[2])); + + if (mask == const0_rtx) + { + emit_move_insn (operands[0], const0_rtx); + DONE; + } + if (mask == constm1_rtx) + { + emit_move_insn (operands[0], operands[1]); + DONE; + } + + operands[1] = force_reg (DImode, operands[1]); + emit_insn (gen_anddi3 (operands[0], operands[1], mask)); + DONE; + } + + operands[1] = force_reg (DImode, operands[1]); + operands[2] = gen_lowpart (QImode, operands[2]); +}) + +(define_insn "*builtin_zapnot_1" + [(set (match_operand:DI 0 "register_operand" "=r") + (and:DI (unspec:DI + [(not:QI (match_operand:QI 2 "register_operand" "r"))] + UNSPEC_ZAP) + (match_operand:DI 1 "reg_or_0_operand" "rJ")))] + "" + "zapnot %r1,%2,%0" + [(set_attr "type" "shift")]) + +(define_insn "builtin_amask" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "reg_or_8bit_operand" "rI")] + UNSPEC_AMASK))] + "" + "amask %1,%0" + [(set_attr "type" "ilog")]) + +(define_insn "builtin_implver" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(const_int 0)] UNSPEC_IMPLVER))] + "" + "implver %0" + [(set_attr "type" "ilog")]) + +(define_insn "builtin_rpcc" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec_volatile:DI [(const_int 0)] UNSPECV_RPCC))] + "" + "rpcc %0" + [(set_attr "type" "ilog")]) + +(define_expand "builtin_minub8" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_0_operand" "")] + "TARGET_MAX" +{ + alpha_expand_builtin_vector_binop (gen_uminv8qi3, V8QImode, operands[0], + operands[1], operands[2]); + DONE; +}) + +(define_expand "builtin_minsb8" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_0_operand" "")] + "TARGET_MAX" +{ + alpha_expand_builtin_vector_binop (gen_sminv8qi3, V8QImode, operands[0], + operands[1], operands[2]); + DONE; +}) + +(define_expand "builtin_minuw4" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_0_operand" "")] + "TARGET_MAX" +{ + alpha_expand_builtin_vector_binop (gen_uminv4hi3, V4HImode, operands[0], + operands[1], operands[2]); + DONE; +}) + +(define_expand "builtin_minsw4" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_0_operand" "")] + "TARGET_MAX" +{ + alpha_expand_builtin_vector_binop (gen_sminv4hi3, V4HImode, operands[0], + operands[1], operands[2]); + DONE; +}) + +(define_expand "builtin_maxub8" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_0_operand" "")] + "TARGET_MAX" +{ + alpha_expand_builtin_vector_binop (gen_umaxv8qi3, V8QImode, operands[0], + operands[1], operands[2]); + DONE; +}) + +(define_expand "builtin_maxsb8" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_0_operand" "")] + "TARGET_MAX" +{ + alpha_expand_builtin_vector_binop (gen_smaxv8qi3, V8QImode, operands[0], + operands[1], operands[2]); + DONE; +}) + +(define_expand "builtin_maxuw4" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_0_operand" "")] + "TARGET_MAX" +{ + alpha_expand_builtin_vector_binop (gen_umaxv4hi3, V4HImode, operands[0], + operands[1], operands[2]); + DONE; +}) + +(define_expand "builtin_maxsw4" + [(match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "reg_or_0_operand" "") + (match_operand:DI 2 "reg_or_0_operand" "")] + "TARGET_MAX" +{ + alpha_expand_builtin_vector_binop (gen_smaxv4hi3, V4HImode, operands[0], + operands[1], operands[2]); + DONE; +}) + +(define_insn "builtin_perr" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "reg_or_0_operand" "%rJ") + (match_operand:DI 2 "reg_or_8bit_operand" "rJ")] + UNSPEC_PERR))] + "TARGET_MAX" + "perr %r1,%r2,%0" + [(set_attr "type" "mvi")]) + +(define_expand "builtin_pklb" + [(set (match_operand:DI 0 "register_operand" "") + (vec_concat:V8QI + (vec_concat:V4QI + (truncate:V2QI (match_operand:DI 1 "register_operand" "")) + (match_dup 2)) + (match_dup 3)))] + "TARGET_MAX" +{ + operands[0] = gen_lowpart (V8QImode, operands[0]); + operands[1] = gen_lowpart (V2SImode, operands[1]); + operands[2] = CONST0_RTX (V2QImode); + operands[3] = CONST0_RTX (V4QImode); +}) + +(define_insn "*pklb" + [(set (match_operand:V8QI 0 "register_operand" "=r") + (vec_concat:V8QI + (vec_concat:V4QI + (truncate:V2QI (match_operand:V2SI 1 "register_operand" "r")) + (match_operand:V2QI 2 "const0_operand" "")) + (match_operand:V4QI 3 "const0_operand" "")))] + "TARGET_MAX" + "pklb %r1,%0" + [(set_attr "type" "mvi")]) + +(define_expand "builtin_pkwb" + [(set (match_operand:DI 0 "register_operand" "") + (vec_concat:V8QI + (truncate:V4QI (match_operand:DI 1 "register_operand" "")) + (match_dup 2)))] + "TARGET_MAX" +{ + operands[0] = gen_lowpart (V8QImode, operands[0]); + operands[1] = gen_lowpart (V4HImode, operands[1]); + operands[2] = CONST0_RTX (V4QImode); +}) + +(define_insn "*pkwb" + [(set (match_operand:V8QI 0 "register_operand" "=r") + (vec_concat:V8QI + (truncate:V4QI (match_operand:V4HI 1 "register_operand" "r")) + (match_operand:V4QI 2 "const0_operand" "")))] + "TARGET_MAX" + "pkwb %r1,%0" + [(set_attr "type" "mvi")]) + +(define_expand "builtin_unpkbl" + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:V2SI + (vec_select:V2QI (match_operand:DI 1 "register_operand" "") + (parallel [(const_int 0) (const_int 1)]))))] + "TARGET_MAX" +{ + operands[0] = gen_lowpart (V2SImode, operands[0]); + operands[1] = gen_lowpart (V8QImode, operands[1]); +}) + +(define_insn "*unpkbl" + [(set (match_operand:V2SI 0 "register_operand" "=r") + (zero_extend:V2SI + (vec_select:V2QI (match_operand:V8QI 1 "reg_or_0_operand" "rW") + (parallel [(const_int 0) (const_int 1)]))))] + "TARGET_MAX" + "unpkbl %r1,%0" + [(set_attr "type" "mvi")]) + +(define_expand "builtin_unpkbw" + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:V4HI + (vec_select:V4QI (match_operand:DI 1 "register_operand" "") + (parallel [(const_int 0) + (const_int 1) + (const_int 2) + (const_int 3)]))))] + "TARGET_MAX" +{ + operands[0] = gen_lowpart (V4HImode, operands[0]); + operands[1] = gen_lowpart (V8QImode, operands[1]); +}) + +(define_insn "*unpkbw" + [(set (match_operand:V4HI 0 "register_operand" "=r") + (zero_extend:V4HI + (vec_select:V4QI (match_operand:V8QI 1 "reg_or_0_operand" "rW") + (parallel [(const_int 0) + (const_int 1) + (const_int 2) + (const_int 3)]))))] + "TARGET_MAX" + "unpkbw %r1,%0" + [(set_attr "type" "mvi")]) + +(include "sync.md") + +;; The call patterns are at the end of the file because their +;; wildcard operand0 interferes with nice recognition. + +(define_insn "*call_value_osf_1_er_noreturn" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "call_operand" "c,R,s")) + (match_operand 2 "" ""))) + (use (reg:DI 29)) + (clobber (reg:DI 26))] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF + && find_reg_note (insn, REG_NORETURN, NULL_RTX)" + "@ + jsr $26,($27),0 + bsr $26,%1\t\t!samegp + ldq $27,%1($29)\t\t!literal!%#\;jsr $26,($27),%1\t\t!lituse_jsr!%#" + [(set_attr "type" "jsr") + (set_attr "length" "*,*,8")]) + +(define_insn "*call_value_osf_1_er" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "call_operand" "c,R,s")) + (match_operand 2 "" ""))) + (use (reg:DI 29)) + (clobber (reg:DI 26))] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "@ + jsr $26,(%1),0\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%* + bsr $26,%1\t\t!samegp + ldq $27,%1($29)\t\t!literal!%#\;jsr $26,($27),0\t\t!lituse_jsr!%#\;ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*" + [(set_attr "type" "jsr") + (set_attr "length" "12,*,16")]) + +;; We must use peep2 instead of a split because we need accurate life +;; information for $gp. Consider the case of { bar(); while (1); }. +(define_peephole2 + [(parallel [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "call_operand" "")) + (match_operand 2 "" ""))) + (use (reg:DI 29)) + (clobber (reg:DI 26))])] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF && reload_completed + && ! samegp_function_operand (operands[1], Pmode) + && (peep2_regno_dead_p (1, 29) + || find_reg_note (insn, REG_NORETURN, NULL_RTX))" + [(parallel [(set (match_dup 0) + (call (mem:DI (match_dup 3)) + (match_dup 2))) + (use (reg:DI 29)) + (use (match_dup 1)) + (use (match_dup 4)) + (clobber (reg:DI 26))])] +{ + if (CONSTANT_P (operands[1])) + { + operands[3] = gen_rtx_REG (Pmode, 27); + operands[4] = GEN_INT (alpha_next_sequence_number++); + emit_insn (gen_movdi_er_high_g (operands[3], pic_offset_table_rtx, + operands[1], operands[4])); + } + else + { + operands[3] = operands[1]; + operands[1] = const0_rtx; + operands[4] = const0_rtx; + } +}) + +(define_peephole2 + [(parallel [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "call_operand" "")) + (match_operand 2 "" ""))) + (use (reg:DI 29)) + (clobber (reg:DI 26))])] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF && reload_completed + && ! samegp_function_operand (operands[1], Pmode) + && ! (peep2_regno_dead_p (1, 29) + || find_reg_note (insn, REG_NORETURN, NULL_RTX))" + [(parallel [(set (match_dup 0) + (call (mem:DI (match_dup 3)) + (match_dup 2))) + (set (match_dup 6) + (unspec:DI [(match_dup 6) (match_dup 4)] UNSPEC_LDGP1)) + (use (match_dup 1)) + (use (match_dup 5)) + (clobber (reg:DI 26))]) + (set (match_dup 6) + (unspec:DI [(match_dup 6) (match_dup 4)] UNSPEC_LDGP2))] +{ + if (CONSTANT_P (operands[1])) + { + operands[3] = gen_rtx_REG (Pmode, 27); + operands[5] = GEN_INT (alpha_next_sequence_number++); + emit_insn (gen_movdi_er_high_g (operands[3], pic_offset_table_rtx, + operands[1], operands[5])); + } + else + { + operands[3] = operands[1]; + operands[1] = const0_rtx; + operands[5] = const0_rtx; + } + operands[4] = GEN_INT (alpha_next_sequence_number++); + operands[6] = pic_offset_table_rtx; +}) + +(define_insn "*call_value_osf_2_er_nogp" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "register_operand" "c")) + (match_operand 2 "" ""))) + (use (reg:DI 29)) + (use (match_operand 3 "" "")) + (use (match_operand 4 "" "")) + (clobber (reg:DI 26))] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "jsr $26,(%1),%3%J4" + [(set_attr "type" "jsr")]) + +(define_insn "*call_value_osf_2_er" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "register_operand" "c")) + (match_operand 2 "" ""))) + (set (reg:DI 29) + (unspec:DI [(reg:DI 29) (match_operand 5 "const_int_operand" "")] + UNSPEC_LDGP1)) + (use (match_operand 3 "" "")) + (use (match_operand 4 "" "")) + (clobber (reg:DI 26))] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "jsr $26,(%1),%3%J4\;ldah $29,0($26)\t\t!gpdisp!%5" + [(set_attr "type" "jsr") + (set_attr "cannot_copy" "true") + (set_attr "length" "8")]) + +(define_insn "*call_value_osf_1_noreturn" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "call_operand" "c,R,s")) + (match_operand 2 "" ""))) + (use (reg:DI 29)) + (clobber (reg:DI 26))] + "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF + && find_reg_note (insn, REG_NORETURN, NULL_RTX)" + "@ + jsr $26,($27),0 + bsr $26,$%1..ng + jsr $26,%1" + [(set_attr "type" "jsr") + (set_attr "length" "*,*,8")]) + +(define_insn_and_split "call_value_osf_tlsgd" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "symbolic_operand" "")) + (const_int 0))) + (unspec [(match_operand:DI 2 "const_int_operand" "")] UNSPEC_TLSGD_CALL) + (use (reg:DI 29)) + (clobber (reg:DI 26))] + "HAVE_AS_TLS" + "#" + "&& reload_completed" + [(set (match_dup 3) + (unspec:DI [(match_dup 5) + (match_dup 1) + (match_dup 2)] UNSPEC_LITERAL)) + (parallel [(set (match_dup 0) + (call (mem:DI (match_dup 3)) + (const_int 0))) + (set (match_dup 5) + (unspec:DI [(match_dup 5) (match_dup 4)] UNSPEC_LDGP1)) + (use (match_dup 1)) + (use (unspec [(match_dup 2)] UNSPEC_TLSGD_CALL)) + (clobber (reg:DI 26))]) + (set (match_dup 5) + (unspec:DI [(match_dup 5) (match_dup 4)] UNSPEC_LDGP2))] +{ + operands[3] = gen_rtx_REG (Pmode, 27); + operands[4] = GEN_INT (alpha_next_sequence_number++); + operands[5] = pic_offset_table_rtx; +} + [(set_attr "type" "multi")]) + +(define_insn_and_split "call_value_osf_tlsldm" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "symbolic_operand" "")) + (const_int 0))) + (unspec [(match_operand:DI 2 "const_int_operand" "")] UNSPEC_TLSLDM_CALL) + (use (reg:DI 29)) + (clobber (reg:DI 26))] + "HAVE_AS_TLS" + "#" + "&& reload_completed" + [(set (match_dup 3) + (unspec:DI [(match_dup 5) + (match_dup 1) + (match_dup 2)] UNSPEC_LITERAL)) + (parallel [(set (match_dup 0) + (call (mem:DI (match_dup 3)) + (const_int 0))) + (set (match_dup 5) + (unspec:DI [(match_dup 5) (match_dup 4)] UNSPEC_LDGP1)) + (use (match_dup 1)) + (use (unspec [(match_dup 2)] UNSPEC_TLSLDM_CALL)) + (clobber (reg:DI 26))]) + (set (match_dup 5) + (unspec:DI [(match_dup 5) (match_dup 4)] UNSPEC_LDGP2))] +{ + operands[3] = gen_rtx_REG (Pmode, 27); + operands[4] = GEN_INT (alpha_next_sequence_number++); + operands[5] = pic_offset_table_rtx; +} + [(set_attr "type" "multi")]) + +(define_insn "*call_value_osf_1" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "call_operand" "c,R,s")) + (match_operand 2 "" ""))) + (use (reg:DI 29)) + (clobber (reg:DI 26))] + "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "@ + jsr $26,($27),0\;ldgp $29,0($26) + bsr $26,$%1..ng + jsr $26,%1\;ldgp $29,0($26)" + [(set_attr "type" "jsr") + (set_attr "length" "12,*,16")]) + +(define_insn "*sibcall_value_osf_1_er" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "symbolic_operand" "R,s")) + (match_operand 2 "" ""))) + (unspec [(reg:DI 29)] UNSPEC_SIBCALL)] + "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "@ + br $31,%1\t\t!samegp + ldq $27,%1($29)\t\t!literal!%#\;jmp $31,($27),%1\t\t!lituse_jsr!%#" + [(set_attr "type" "jsr") + (set_attr "length" "*,8")]) + +(define_insn "*sibcall_value_osf_1" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "symbolic_operand" "R,s")) + (match_operand 2 "" ""))) + (unspec [(reg:DI 29)] UNSPEC_SIBCALL)] + "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" + "@ + br $31,$%1..ng + lda $27,%1\;jmp $31,($27),%1" + [(set_attr "type" "jsr") + (set_attr "length" "*,8")]) + +(define_insn "*call_value_nt_1" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "call_operand" "r,R,s")) + (match_operand 2 "" ""))) + (clobber (reg:DI 26))] + "TARGET_ABI_WINDOWS_NT" + "@ + jsr $26,(%1) + bsr $26,%1 + jsr $26,%1" + [(set_attr "type" "jsr") + (set_attr "length" "*,*,12")]) + +; GAS relies on the order and position of instructions output below in order +; to generate relocs for VMS link to potentially optimize the call. +; Please do not molest. +(define_insn "*call_value_vms_1" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "call_operand" "r,s")) + (match_operand 2 "" ""))) + (use (match_operand:DI 3 "nonmemory_operand" "r,n")) + (use (reg:DI 25)) + (use (reg:DI 26)) + (clobber (reg:DI 27))] + "TARGET_ABI_OPEN_VMS" +{ + switch (which_alternative) + { + case 0: + return "mov %3,$27\;jsr $26,0\;ldq $27,0($29)"; + case 1: + operands [3] = alpha_use_linkage (operands [1], cfun->decl, 1, 0); + operands [4] = alpha_use_linkage (operands [1], cfun->decl, 0, 0); + return "ldq $26,%4\;ldq $27,%3\;jsr $26,%1\;ldq $27,0($29)"; + default: + gcc_unreachable (); + } +} + [(set_attr "type" "jsr") + (set_attr "length" "12,16")]) + +(define_insn "*call_value_umk" + [(set (match_operand 0 "" "") + (call (mem:DI (match_operand:DI 1 "call_operand" "r")) + (match_operand 2 "" ""))) + (use (reg:DI 25)) + (clobber (reg:DI 26))] + "TARGET_ABI_UNICOSMK" + "jsr $26,(%1)" + [(set_attr "type" "jsr")]) |