;; Machine description for AArch64 AdvSIMD architecture.
;; Copyright (C) 2011-2014 Free Software Foundation, Inc.
;; Contributed by ARM Ltd.
;;
;; 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
;; .
(define_expand "mov"
[(set (match_operand:VALL 0 "nonimmediate_operand" "")
(match_operand:VALL 1 "general_operand" ""))]
"TARGET_SIMD"
"
if (GET_CODE (operands[0]) == MEM)
operands[1] = force_reg (mode, operands[1]);
"
)
(define_expand "movmisalign"
[(set (match_operand:VALL 0 "nonimmediate_operand" "")
(match_operand:VALL 1 "general_operand" ""))]
"TARGET_SIMD"
{
/* This pattern is not permitted to fail during expansion: if both arguments
are non-registers (e.g. memory := constant, which can be created by the
auto-vectorizer), force operand 1 into a register. */
if (!register_operand (operands[0], mode)
&& !register_operand (operands[1], mode))
operands[1] = force_reg (mode, operands[1]);
})
(define_insn "aarch64_simd_dup"
[(set (match_operand:VDQ 0 "register_operand" "=w, w")
(vec_duplicate:VDQ (match_operand: 1 "register_operand" "r, w")))]
"TARGET_SIMD"
"@
dup\\t%0., %1
dup\\t%0., %1.[0]"
[(set_attr "type" "neon_from_gp, neon_dup")]
)
(define_insn "aarch64_simd_dup"
[(set (match_operand:VDQF 0 "register_operand" "=w")
(vec_duplicate:VDQF (match_operand: 1 "register_operand" "w")))]
"TARGET_SIMD"
"dup\\t%0., %1.[0]"
[(set_attr "type" "neon_dup")]
)
(define_insn "aarch64_dup_lane"
[(set (match_operand:VALL 0 "register_operand" "=w")
(vec_duplicate:VALL
(vec_select:
(match_operand:VALL 1 "register_operand" "w")
(parallel [(match_operand:SI 2 "immediate_operand" "i")])
)))]
"TARGET_SIMD"
{
operands[2] = GEN_INT (ENDIAN_LANE_N (mode, INTVAL (operands[2])));
return "dup\\t%0., %1.[%2]";
}
[(set_attr "type" "neon_dup")]
)
(define_insn "aarch64_dup_lane_"
[(set (match_operand:VALL 0 "register_operand" "=w")
(vec_duplicate:VALL
(vec_select:
(match_operand: 1 "register_operand" "w")
(parallel [(match_operand:SI 2 "immediate_operand" "i")])
)))]
"TARGET_SIMD"
{
operands[2] = GEN_INT (ENDIAN_LANE_N (mode,
INTVAL (operands[2])));
return "dup\\t%0., %1.[%2]";
}
[(set_attr "type" "neon_dup")]
)
(define_insn "*aarch64_simd_mov"
[(set (match_operand:VD 0 "nonimmediate_operand"
"=w, m, w, ?r, ?w, ?r, w")
(match_operand:VD 1 "general_operand"
"m, w, w, w, r, r, Dn"))]
"TARGET_SIMD
&& (register_operand (operands[0], mode)
|| register_operand (operands[1], mode))"
{
switch (which_alternative)
{
case 0: return "ldr\\t%d0, %1";
case 1: return "str\\t%d1, %0";
case 2: return "orr\t%0., %1., %1.";
case 3: return "umov\t%0, %1.d[0]";
case 4: return "ins\t%0.d[0], %1";
case 5: return "mov\t%0, %1";
case 6:
return aarch64_output_simd_mov_immediate (operands[1],
mode, 64);
default: gcc_unreachable ();
}
}
[(set_attr "type" "neon_load1_1reg, neon_store1_1reg,\
neon_logic, neon_to_gp, neon_from_gp,\
mov_reg, neon_move")]
)
(define_insn "*aarch64_simd_mov"
[(set (match_operand:VQ 0 "nonimmediate_operand"
"=w, m, w, ?r, ?w, ?r, w")
(match_operand:VQ 1 "general_operand"
"m, w, w, w, r, r, Dn"))]
"TARGET_SIMD
&& (register_operand (operands[0], mode)
|| register_operand (operands[1], mode))"
{
switch (which_alternative)
{
case 0:
return "ldr\\t%q0, %1";
case 1:
return "str\\t%q1, %0";
case 2:
return "orr\t%0., %1., %1.";
case 3:
case 4:
case 5:
return "#";
case 6:
return aarch64_output_simd_mov_immediate (operands[1], mode, 128);
default:
gcc_unreachable ();
}
}
[(set_attr "type" "neon_load1_1reg, neon_store1_1reg,\
neon_logic, multiple, multiple, multiple,\
neon_move")
(set_attr "length" "4,4,4,8,8,8,4")]
)
(define_split
[(set (match_operand:VQ 0 "register_operand" "")
(match_operand:VQ 1 "register_operand" ""))]
"TARGET_SIMD && reload_completed
&& GP_REGNUM_P (REGNO (operands[0]))
&& GP_REGNUM_P (REGNO (operands[1]))"
[(set (match_dup 0) (match_dup 1))
(set (match_dup 2) (match_dup 3))]
{
int rdest = REGNO (operands[0]);
int rsrc = REGNO (operands[1]);
rtx dest[2], src[2];
dest[0] = gen_rtx_REG (DImode, rdest);
src[0] = gen_rtx_REG (DImode, rsrc);
dest[1] = gen_rtx_REG (DImode, rdest + 1);
src[1] = gen_rtx_REG (DImode, rsrc + 1);
aarch64_simd_disambiguate_copy (operands, dest, src, 2);
})
(define_split
[(set (match_operand:VQ 0 "register_operand" "")
(match_operand:VQ 1 "register_operand" ""))]
"TARGET_SIMD && reload_completed
&& ((FP_REGNUM_P (REGNO (operands[0])) && GP_REGNUM_P (REGNO (operands[1])))
|| (GP_REGNUM_P (REGNO (operands[0])) && FP_REGNUM_P (REGNO (operands[1]))))"
[(const_int 0)]
{
aarch64_split_simd_move (operands[0], operands[1]);
DONE;
})
(define_expand "aarch64_split_simd_mov"
[(set (match_operand:VQ 0)
(match_operand:VQ 1))]
"TARGET_SIMD"
{
rtx dst = operands[0];
rtx src = operands[1];
if (GP_REGNUM_P (REGNO (src)))
{
rtx src_low_part = gen_lowpart (mode, src);
rtx src_high_part = gen_highpart (mode, src);
emit_insn
(gen_move_lo_quad_ (dst, src_low_part));
emit_insn
(gen_move_hi_quad_ (dst, src_high_part));
}
else
{
rtx dst_low_part = gen_lowpart (mode, dst);
rtx dst_high_part = gen_highpart (mode, dst);
rtx lo = aarch64_simd_vect_par_cnst_half (mode, false);
rtx hi = aarch64_simd_vect_par_cnst_half (mode, true);
emit_insn
(gen_aarch64_simd_mov_from_low (dst_low_part, src, lo));
emit_insn
(gen_aarch64_simd_mov_from_high (dst_high_part, src, hi));
}
DONE;
}
)
(define_insn "aarch64_simd_mov_from_low"
[(set (match_operand: 0 "register_operand" "=r")
(vec_select:
(match_operand:VQ 1 "register_operand" "w")
(match_operand:VQ 2 "vect_par_cnst_lo_half" "")))]
"TARGET_SIMD && reload_completed"
"umov\t%0, %1.d[0]"
[(set_attr "type" "neon_to_gp")
(set_attr "length" "4")
])
(define_insn "aarch64_simd_mov_from_high"
[(set (match_operand: 0 "register_operand" "=r")
(vec_select:
(match_operand:VQ 1 "register_operand" "w")
(match_operand:VQ 2 "vect_par_cnst_hi_half" "")))]
"TARGET_SIMD && reload_completed"
"umov\t%0, %1.d[1]"
[(set_attr "type" "neon_to_gp")
(set_attr "length" "4")
])
(define_insn "orn3"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(ior:VDQ (not:VDQ (match_operand:VDQ 1 "register_operand" "w"))
(match_operand:VDQ 2 "register_operand" "w")))]
"TARGET_SIMD"
"orn\t%0., %2., %1."
[(set_attr "type" "neon_logic")]
)
(define_insn "bic3"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(and:VDQ (not:VDQ (match_operand:VDQ 1 "register_operand" "w"))
(match_operand:VDQ 2 "register_operand" "w")))]
"TARGET_SIMD"
"bic\t%0., %2., %1."
[(set_attr "type" "neon_logic")]
)
(define_insn "add3"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(plus:VDQ (match_operand:VDQ 1 "register_operand" "w")
(match_operand:VDQ 2 "register_operand" "w")))]
"TARGET_SIMD"
"add\t%0., %1., %2."
[(set_attr "type" "neon_add")]
)
(define_insn "sub3"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(minus:VDQ (match_operand:VDQ 1 "register_operand" "w")
(match_operand:VDQ 2 "register_operand" "w")))]
"TARGET_SIMD"
"sub\t%0., %1., %2."
[(set_attr "type" "neon_sub")]
)
(define_insn "mul3"
[(set (match_operand:VDQM 0 "register_operand" "=w")
(mult:VDQM (match_operand:VDQM 1 "register_operand" "w")
(match_operand:VDQM 2 "register_operand" "w")))]
"TARGET_SIMD"
"mul\t%0., %1., %2."
[(set_attr "type" "neon_mul_")]
)
(define_insn "bswap"
[(set (match_operand:VDQHSD 0 "register_operand" "=w")
(bswap:VDQHSD (match_operand:VDQHSD 1 "register_operand" "w")))]
"TARGET_SIMD"
"rev\\t%0., %1."
[(set_attr "type" "neon_rev")]
)
(define_insn "aarch64_rbit"
[(set (match_operand:VB 0 "register_operand" "=w")
(unspec:VB [(match_operand:VB 1 "register_operand" "w")]
UNSPEC_RBIT))]
"TARGET_SIMD"
"rbit\\t%0., %1."
[(set_attr "type" "neon_rbit")]
)
(define_insn "*aarch64_mul3_elt"
[(set (match_operand:VMUL 0 "register_operand" "=w")
(mult:VMUL
(vec_duplicate:VMUL
(vec_select:
(match_operand:VMUL 1 "register_operand" "")
(parallel [(match_operand:SI 2 "immediate_operand")])))
(match_operand:VMUL 3 "register_operand" "w")))]
"TARGET_SIMD"
{
operands[2] = GEN_INT (ENDIAN_LANE_N (mode, INTVAL (operands[2])));
return "mul\\t%0., %3., %1.[%2]";
}
[(set_attr "type" "neon_mul__scalar")]
)
(define_insn "*aarch64_mul3_elt_"
[(set (match_operand:VMUL_CHANGE_NLANES 0 "register_operand" "=w")
(mult:VMUL_CHANGE_NLANES
(vec_duplicate:VMUL_CHANGE_NLANES
(vec_select:
(match_operand: 1 "register_operand" "")
(parallel [(match_operand:SI 2 "immediate_operand")])))
(match_operand:VMUL_CHANGE_NLANES 3 "register_operand" "w")))]
"TARGET_SIMD"
{
operands[2] = GEN_INT (ENDIAN_LANE_N (mode,
INTVAL (operands[2])));
return "mul\\t%0., %3., %1.[%2]";
}
[(set_attr "type" "neon_mul__scalar")]
)
(define_insn "*aarch64_mul3_elt_to_128df"
[(set (match_operand:V2DF 0 "register_operand" "=w")
(mult:V2DF
(vec_duplicate:V2DF
(match_operand:DF 2 "register_operand" "w"))
(match_operand:V2DF 1 "register_operand" "w")))]
"TARGET_SIMD"
"fmul\\t%0.2d, %1.2d, %2.d[0]"
[(set_attr "type" "neon_fp_mul_d_scalar_q")]
)
(define_insn "*aarch64_mul3_elt_to_64v2df"
[(set (match_operand:DF 0 "register_operand" "=w")
(mult:DF
(vec_select:DF
(match_operand:V2DF 1 "register_operand" "w")
(parallel [(match_operand:SI 2 "immediate_operand")]))
(match_operand:DF 3 "register_operand" "w")))]
"TARGET_SIMD"
{
operands[2] = GEN_INT (ENDIAN_LANE_N (V2DFmode, INTVAL (operands[2])));
return "fmul\\t%0.2d, %3.2d, %1.d[%2]";
}
[(set_attr "type" "neon_fp_mul_d_scalar_q")]
)
(define_insn "neg2"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(neg:VDQ (match_operand:VDQ 1 "register_operand" "w")))]
"TARGET_SIMD"
"neg\t%0., %1."
[(set_attr "type" "neon_neg")]
)
(define_insn "abs2"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(abs:VDQ (match_operand:VDQ 1 "register_operand" "w")))]
"TARGET_SIMD"
"abs\t%0., %1."
[(set_attr "type" "neon_abs")]
)
(define_insn "abd_3"
[(set (match_operand:VDQ_BHSI 0 "register_operand" "=w")
(abs:VDQ_BHSI (minus:VDQ_BHSI
(match_operand:VDQ_BHSI 1 "register_operand" "w")
(match_operand:VDQ_BHSI 2 "register_operand" "w"))))]
"TARGET_SIMD"
"sabd\t%0., %1., %2."
[(set_attr "type" "neon_abd")]
)
(define_insn "aba_3"
[(set (match_operand:VDQ_BHSI 0 "register_operand" "=w")
(plus:VDQ_BHSI (abs:VDQ_BHSI (minus:VDQ_BHSI
(match_operand:VDQ_BHSI 1 "register_operand" "w")
(match_operand:VDQ_BHSI 2 "register_operand" "w")))
(match_operand:VDQ_BHSI 3 "register_operand" "0")))]
"TARGET_SIMD"
"saba\t%0., %1., %2."
[(set_attr "type" "neon_arith_acc")]
)
(define_insn "fabd_3"
[(set (match_operand:VDQF 0 "register_operand" "=w")
(abs:VDQF (minus:VDQF
(match_operand:VDQF 1 "register_operand" "w")
(match_operand:VDQF 2 "register_operand" "w"))))]
"TARGET_SIMD"
"fabd\t%0., %1., %2."
[(set_attr "type" "neon_fp_abd_")]
)
(define_insn "*fabd_scalar3"
[(set (match_operand:GPF 0 "register_operand" "=w")
(abs:GPF (minus:GPF
(match_operand:GPF 1 "register_operand" "w")
(match_operand:GPF 2 "register_operand" "w"))))]
"TARGET_SIMD"
"fabd\t%0, %1, %2"
[(set_attr "type" "neon_fp_abd_")]
)
(define_insn "and3"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(and:VDQ (match_operand:VDQ 1 "register_operand" "w")
(match_operand:VDQ 2 "register_operand" "w")))]
"TARGET_SIMD"
"and\t%0., %1., %2."
[(set_attr "type" "neon_logic")]
)
(define_insn "ior3"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(ior:VDQ (match_operand:VDQ 1 "register_operand" "w")
(match_operand:VDQ 2 "register_operand" "w")))]
"TARGET_SIMD"
"orr\t%0., %1., %2."
[(set_attr "type" "neon_logic")]
)
(define_insn "xor3"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(xor:VDQ (match_operand:VDQ 1 "register_operand" "w")
(match_operand:VDQ 2 "register_operand" "w")))]
"TARGET_SIMD"
"eor\t%0., %1., %2."
[(set_attr "type" "neon_logic")]
)
(define_insn "one_cmpl2"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(not:VDQ (match_operand:VDQ 1 "register_operand" "w")))]
"TARGET_SIMD"
"not\t%0., %1."
[(set_attr "type" "neon_logic")]
)
(define_insn "aarch64_simd_vec_set"
[(set (match_operand:VQ_S 0 "register_operand" "=w,w")
(vec_merge:VQ_S
(vec_duplicate:VQ_S
(match_operand: 1 "register_operand" "r,w"))
(match_operand:VQ_S 3 "register_operand" "0,0")
(match_operand:SI 2 "immediate_operand" "i,i")))]
"TARGET_SIMD"
{
int elt = ENDIAN_LANE_N (mode, exact_log2 (INTVAL (operands[2])));
operands[2] = GEN_INT ((HOST_WIDE_INT) 1 << elt);
switch (which_alternative)
{
case 0:
return "ins\\t%0.[%p2], %w1";
case 1:
return "ins\\t%0.[%p2], %1.[0]";
default:
gcc_unreachable ();
}
}
[(set_attr "type" "neon_from_gp, neon_ins")]
)
(define_insn "aarch64_simd_lshr"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(lshiftrt:VDQ (match_operand:VDQ 1 "register_operand" "w")
(match_operand:VDQ 2 "aarch64_simd_rshift_imm" "Dr")))]
"TARGET_SIMD"
"ushr\t%0., %1., %2"
[(set_attr "type" "neon_shift_imm")]
)
(define_insn "aarch64_simd_ashr"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(ashiftrt:VDQ (match_operand:VDQ 1 "register_operand" "w")
(match_operand:VDQ 2 "aarch64_simd_rshift_imm" "Dr")))]
"TARGET_SIMD"
"sshr\t%0., %1., %2"
[(set_attr "type" "neon_shift_imm")]
)
(define_insn "aarch64_simd_imm_shl"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(ashift:VDQ (match_operand:VDQ 1 "register_operand" "w")
(match_operand:VDQ 2 "aarch64_simd_lshift_imm" "Dl")))]
"TARGET_SIMD"
"shl\t%0., %1., %2"
[(set_attr "type" "neon_shift_imm")]
)
(define_insn "aarch64_simd_reg_sshl"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(ashift:VDQ (match_operand:VDQ 1 "register_operand" "w")
(match_operand:VDQ 2 "register_operand" "w")))]
"TARGET_SIMD"
"sshl\t%0., %1., %2."
[(set_attr "type" "neon_shift_reg")]
)
(define_insn "aarch64_simd_reg_shl_unsigned"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(unspec:VDQ [(match_operand:VDQ 1 "register_operand" "w")
(match_operand:VDQ 2 "register_operand" "w")]
UNSPEC_ASHIFT_UNSIGNED))]
"TARGET_SIMD"
"ushl\t%0., %1., %2."
[(set_attr "type" "neon_shift_reg")]
)
(define_insn "aarch64_simd_reg_shl_signed"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(unspec:VDQ [(match_operand:VDQ 1 "register_operand" "w")
(match_operand:VDQ 2 "register_operand" "w")]
UNSPEC_ASHIFT_SIGNED))]
"TARGET_SIMD"
"sshl\t%0., %1., %2."
[(set_attr "type" "neon_shift_reg")]
)
(define_expand "ashl3"
[(match_operand:VDQ 0 "register_operand" "")
(match_operand:VDQ 1 "register_operand" "")
(match_operand:SI 2 "general_operand" "")]
"TARGET_SIMD"
{
int bit_width = GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT;
int shift_amount;
if (CONST_INT_P (operands[2]))
{
shift_amount = INTVAL (operands[2]);
if (shift_amount >= 0 && shift_amount < bit_width)
{
rtx tmp = aarch64_simd_gen_const_vector_dup (mode,
shift_amount);
emit_insn (gen_aarch64_simd_imm_shl (operands[0],
operands[1],
tmp));
DONE;
}
else
{
operands[2] = force_reg (SImode, operands[2]);
}
}
else if (MEM_P (operands[2]))
{
operands[2] = force_reg (SImode, operands[2]);
}
if (REG_P (operands[2]))
{
rtx tmp = gen_reg_rtx (mode);
emit_insn (gen_aarch64_simd_dup (tmp,
convert_to_mode (mode,
operands[2],
0)));
emit_insn (gen_aarch64_simd_reg_sshl (operands[0], operands[1],
tmp));
DONE;
}
else
FAIL;
}
)
(define_expand "lshr3"
[(match_operand:VDQ 0 "register_operand" "")
(match_operand:VDQ 1 "register_operand" "")
(match_operand:SI 2 "general_operand" "")]
"TARGET_SIMD"
{
int bit_width = GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT;
int shift_amount;
if (CONST_INT_P (operands[2]))
{
shift_amount = INTVAL (operands[2]);
if (shift_amount > 0 && shift_amount <= bit_width)
{
rtx tmp = aarch64_simd_gen_const_vector_dup (mode,
shift_amount);
emit_insn (gen_aarch64_simd_lshr (operands[0],
operands[1],
tmp));
DONE;
}
else
operands[2] = force_reg (SImode, operands[2]);
}
else if (MEM_P (operands[2]))
{
operands[2] = force_reg (SImode, operands[2]);
}
if (REG_P (operands[2]))
{
rtx tmp = gen_reg_rtx (SImode);
rtx tmp1 = gen_reg_rtx (mode);
emit_insn (gen_negsi2 (tmp, operands[2]));
emit_insn (gen_aarch64_simd_dup (tmp1,
convert_to_mode (mode,
tmp, 0)));
emit_insn (gen_aarch64_simd_reg_shl_unsigned (operands[0],
operands[1],
tmp1));
DONE;
}
else
FAIL;
}
)
(define_expand "ashr3"
[(match_operand:VDQ 0 "register_operand" "")
(match_operand:VDQ 1 "register_operand" "")
(match_operand:SI 2 "general_operand" "")]
"TARGET_SIMD"
{
int bit_width = GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT;
int shift_amount;
if (CONST_INT_P (operands[2]))
{
shift_amount = INTVAL (operands[2]);
if (shift_amount > 0 && shift_amount <= bit_width)
{
rtx tmp = aarch64_simd_gen_const_vector_dup (mode,
shift_amount);
emit_insn (gen_aarch64_simd_ashr (operands[0],
operands[1],
tmp));
DONE;
}
else
operands[2] = force_reg (SImode, operands[2]);
}
else if (MEM_P (operands[2]))
{
operands[2] = force_reg (SImode, operands[2]);
}
if (REG_P (operands[2]))
{
rtx tmp = gen_reg_rtx (SImode);
rtx tmp1 = gen_reg_rtx (mode);
emit_insn (gen_negsi2 (tmp, operands[2]));
emit_insn (gen_aarch64_simd_dup (tmp1,
convert_to_mode (mode,
tmp, 0)));
emit_insn (gen_aarch64_simd_reg_shl_signed (operands[0],
operands[1],
tmp1));
DONE;
}
else
FAIL;
}
)
(define_expand "vashl3"
[(match_operand:VDQ 0 "register_operand" "")
(match_operand:VDQ 1 "register_operand" "")
(match_operand:VDQ 2 "register_operand" "")]
"TARGET_SIMD"
{
emit_insn (gen_aarch64_simd_reg_sshl (operands[0], operands[1],
operands[2]));
DONE;
})
;; Using mode VQ_S as there is no V2DImode neg!
;; Negating individual lanes most certainly offsets the
;; gain from vectorization.
(define_expand "vashr3"
[(match_operand:VQ_S 0 "register_operand" "")
(match_operand:VQ_S 1 "register_operand" "")
(match_operand:VQ_S 2 "register_operand" "")]
"TARGET_SIMD"
{
rtx neg = gen_reg_rtx (mode);
emit (gen_neg2 (neg, operands[2]));
emit_insn (gen_aarch64_simd_reg_shl_signed (operands[0], operands[1],
neg));
DONE;
})
;; DI vector shift
(define_expand "aarch64_ashr_simddi"
[(match_operand:DI 0 "register_operand" "=w")
(match_operand:DI 1 "register_operand" "w")
(match_operand:SI 2 "aarch64_shift_imm64_di" "")]
"TARGET_SIMD"
{
if (INTVAL (operands[2]) == 64)
emit_insn (gen_aarch64_sshr_simddi (operands[0], operands[1]));
else
emit_insn (gen_ashrdi3 (operands[0], operands[1], operands[2]));
DONE;
}
)
;; SIMD shift by 64. This pattern is a special case as standard pattern does
;; not handle NEON shifts by 64.
(define_insn "aarch64_sshr_simddi"
[(set (match_operand:DI 0 "register_operand" "=w")
(unspec:DI
[(match_operand:DI 1 "register_operand" "w")] UNSPEC_SSHR64))]
"TARGET_SIMD"
"sshr\t%d0, %d1, 64"
[(set_attr "type" "neon_shift_imm")]
)
(define_expand "vlshr3"
[(match_operand:VQ_S 0 "register_operand" "")
(match_operand:VQ_S 1 "register_operand" "")
(match_operand:VQ_S 2 "register_operand" "")]
"TARGET_SIMD"
{
rtx neg = gen_reg_rtx (mode);
emit (gen_neg2 (neg, operands[2]));
emit_insn (gen_aarch64_simd_reg_shl_unsigned (operands[0], operands[1],
neg));
DONE;
})
(define_expand "aarch64_lshr_simddi"
[(match_operand:DI 0 "register_operand" "=w")
(match_operand:DI 1 "register_operand" "w")
(match_operand:SI 2 "aarch64_shift_imm64_di" "")]
"TARGET_SIMD"
{
if (INTVAL (operands[2]) == 64)
emit_insn (gen_aarch64_ushr_simddi (operands[0], operands[1]));
else
emit_insn (gen_lshrdi3 (operands[0], operands[1], operands[2]));
DONE;
}
)
;; SIMD shift by 64. This pattern is a special case as standard pattern does
;; not handle NEON shifts by 64.
(define_insn "aarch64_ushr_simddi"
[(set (match_operand:DI 0 "register_operand" "=w")
(unspec:DI
[(match_operand:DI 1 "register_operand" "w")] UNSPEC_USHR64))]
"TARGET_SIMD"
"ushr\t%d0, %d1, 64"
[(set_attr "type" "neon_shift_imm")]
)
(define_expand "vec_set"
[(match_operand:VQ_S 0 "register_operand")
(match_operand: 1 "register_operand")
(match_operand:SI 2 "immediate_operand")]
"TARGET_SIMD"
{
HOST_WIDE_INT elem = (HOST_WIDE_INT) 1 << INTVAL (operands[2]);
emit_insn (gen_aarch64_simd_vec_set