;; Code iterators
;;----------------------------------------------------------------------------
-;; A list of condition codes used in compare instructions where
-;; the carry flag from the addition is used instead of doing the
+;; A list of condition codes used in compare instructions where
+;; the carry flag from the addition is used instead of doing the
;; compare a second time.
(define_code_iterator LTUGEU [ltu geu])
;; The signed gt, ge comparisons
(define_code_iterator GTGE [gt ge])
+;; The signed gt, ge, lt, le comparisons
+(define_code_iterator GLTE [gt ge lt le])
+
;; The unsigned gt, ge comparisons
(define_code_iterator GTUGEU [gtu geu])
;; Binary operators whose second operand can be shifted.
(define_code_iterator SHIFTABLE_OPS [plus minus ior xor and])
+;; Operations on the sign of a number.
+(define_code_iterator ABSNEG [abs neg])
+
+;; Conversions.
+(define_code_iterator FCVT [unsigned_float float])
+
;; plus and minus are the only SHIFTABLE_OPS for which Thumb2 allows
;; a stack pointer opoerand. The minus operation is a candidate for an rsub
;; and hence only plus is supported.
(define_int_iterator VCVT_US_N [UNSPEC_VCVT_S_N UNSPEC_VCVT_U_N])
+(define_int_iterator VCVT_HF_US_N [UNSPEC_VCVT_HF_S_N UNSPEC_VCVT_HF_U_N])
+
+(define_int_iterator VCVT_SI_US_N [UNSPEC_VCVT_SI_S_N UNSPEC_VCVT_SI_U_N])
+
+(define_int_iterator VCVT_HF_US [UNSPEC_VCVTA_S UNSPEC_VCVTA_U
+ UNSPEC_VCVTM_S UNSPEC_VCVTM_U
+ UNSPEC_VCVTN_S UNSPEC_VCVTN_U
+ UNSPEC_VCVTP_S UNSPEC_VCVTP_U])
+
+(define_int_iterator VCVTH_US [UNSPEC_VCVTH_S UNSPEC_VCVTH_U])
+
+;; Operators for FP16 instructions.
+(define_int_iterator FP16_RND [UNSPEC_VRND UNSPEC_VRNDA
+ UNSPEC_VRNDM UNSPEC_VRNDN
+ UNSPEC_VRNDP UNSPEC_VRNDX])
+
(define_int_iterator VQMOVN [UNSPEC_VQMOVN_S UNSPEC_VQMOVN_U])
(define_int_iterator VMOVL [UNSPEC_VMOVL_S UNSPEC_VMOVL_U])
(define_code_attr shift [(ashiftrt "ashr") (lshiftrt "lshr")])
(define_code_attr shifttype [(ashiftrt "signed") (lshiftrt "unsigned")])
+;; String reprentations of operations on the sign of a number.
+(define_code_attr absneg_str [(abs "abs") (neg "neg")])
+
+;; Conversions.
+(define_code_attr FCVTI32typename [(unsigned_float "u32") (float "s32")])
+
;;----------------------------------------------------------------------------
;; Int attributes
;;----------------------------------------------------------------------------
(UNSPEC_VPMAX "s") (UNSPEC_VPMAX_U "u")
(UNSPEC_VPMIN "s") (UNSPEC_VPMIN_U "u")
(UNSPEC_VCVT_S "s") (UNSPEC_VCVT_U "u")
+ (UNSPEC_VCVTA_S "s") (UNSPEC_VCVTA_U "u")
+ (UNSPEC_VCVTM_S "s") (UNSPEC_VCVTM_U "u")
+ (UNSPEC_VCVTN_S "s") (UNSPEC_VCVTN_U "u")
+ (UNSPEC_VCVTP_S "s") (UNSPEC_VCVTP_U "u")
(UNSPEC_VCVT_S_N "s") (UNSPEC_VCVT_U_N "u")
+ (UNSPEC_VCVT_HF_S_N "s") (UNSPEC_VCVT_HF_U_N "u")
+ (UNSPEC_VCVT_SI_S_N "s") (UNSPEC_VCVT_SI_U_N "u")
(UNSPEC_VQMOVN_S "s") (UNSPEC_VQMOVN_U "u")
(UNSPEC_VMOVL_S "s") (UNSPEC_VMOVL_U "u")
(UNSPEC_VSHL_S "s") (UNSPEC_VSHL_U "u")
(UNSPEC_VSHLL_S_N "s") (UNSPEC_VSHLL_U_N "u")
(UNSPEC_VSRA_S_N "s") (UNSPEC_VSRA_U_N "u")
(UNSPEC_VRSRA_S_N "s") (UNSPEC_VRSRA_U_N "u")
-
+ (UNSPEC_VCVTH_S "s") (UNSPEC_VCVTH_U "u")
])
+(define_int_attr vcvth_op
+ [(UNSPEC_VCVTA_S "a") (UNSPEC_VCVTA_U "a")
+ (UNSPEC_VCVTM_S "m") (UNSPEC_VCVTM_U "m")
+ (UNSPEC_VCVTN_S "n") (UNSPEC_VCVTN_U "n")
+ (UNSPEC_VCVTP_S "p") (UNSPEC_VCVTP_U "p")])
+
+(define_int_attr fp16_rnd_str
+ [(UNSPEC_VRND "rnd") (UNSPEC_VRNDA "rnda")
+ (UNSPEC_VRNDM "rndm") (UNSPEC_VRNDN "rndn")
+ (UNSPEC_VRNDP "rndp") (UNSPEC_VRNDX "rndx")])
+
+(define_int_attr fp16_rnd_insn
+ [(UNSPEC_VRND "vrintz") (UNSPEC_VRNDA "vrinta")
+ (UNSPEC_VRNDM "vrintm") (UNSPEC_VRNDN "vrintn")
+ (UNSPEC_VRNDP "vrintp") (UNSPEC_VRNDX "vrintx")])
+
(define_int_attr cmp_op_unsp [(UNSPEC_VCEQ "eq") (UNSPEC_VCGT "gt")
(UNSPEC_VCGE "ge") (UNSPEC_VCLE "le")
(UNSPEC_VCLT "lt") (UNSPEC_VCAGE "ge")
(set_attr "type" "ffarithd")]
)
+;; ABS and NEG for FP16.
+(define_insn "<absneg_str>hf2"
+ [(set (match_operand:HF 0 "s_register_operand" "=w")
+ (ABSNEG:HF (match_operand:HF 1 "s_register_operand" "w")))]
+ "TARGET_VFP_FP16INST"
+ "v<absneg_str>.f16\t%0, %1"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "ffariths")]
+)
+
+(define_expand "neon_vabshf"
+ [(set
+ (match_operand:HF 0 "s_register_operand")
+ (abs:HF (match_operand:HF 1 "s_register_operand")))]
+ "TARGET_VFP_FP16INST"
+{
+ emit_insn (gen_abshf2 (operands[0], operands[1]));
+ DONE;
+})
+
+;; VRND for FP16.
+(define_insn "neon_v<fp16_rnd_str>hf"
+ [(set (match_operand:HF 0 "s_register_operand" "=w")
+ (unspec:HF
+ [(match_operand:HF 1 "s_register_operand" "w")]
+ FP16_RND))]
+ "TARGET_VFP_FP16INST"
+ "<fp16_rnd_insn>.f16\t%0, %1"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "neon_fp_round_s")]
+)
+
+(define_insn "neon_vrndihf"
+ [(set (match_operand:HF 0 "s_register_operand" "=w")
+ (unspec:HF
+ [(match_operand:HF 1 "s_register_operand" "w")]
+ UNSPEC_VRNDI))]
+ "TARGET_VFP_FP16INST"
+ "vrintr.f16\t%0, %1"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "neon_fp_round_s")]
+)
;; Arithmetic insns
+(define_insn "addhf3"
+ [(set
+ (match_operand:HF 0 "s_register_operand" "=w")
+ (plus:HF
+ (match_operand:HF 1 "s_register_operand" "w")
+ (match_operand:HF 2 "s_register_operand" "w")))]
+ "TARGET_VFP_FP16INST"
+ "vadd.f16\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fadds")]
+)
+
(define_insn "*addsf3_vfp"
[(set (match_operand:SF 0 "s_register_operand" "=t")
(plus:SF (match_operand:SF 1 "s_register_operand" "t")
(set_attr "type" "faddd")]
)
+(define_insn "subhf3"
+ [(set
+ (match_operand:HF 0 "s_register_operand" "=w")
+ (minus:HF
+ (match_operand:HF 1 "s_register_operand" "w")
+ (match_operand:HF 2 "s_register_operand" "w")))]
+ "TARGET_VFP_FP16INST"
+ "vsub.f16\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fadds")]
+)
(define_insn "*subsf3_vfp"
[(set (match_operand:SF 0 "s_register_operand" "=t")
;; Division insns
+;; FP16 Division.
+(define_insn "divhf3"
+ [(set
+ (match_operand:HF 0 "s_register_operand" "=w")
+ (div:HF
+ (match_operand:HF 1 "s_register_operand" "w")
+ (match_operand:HF 2 "s_register_operand" "w")))]
+ "TARGET_VFP_FP16INST"
+ "vdiv.f16\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fdivs")]
+)
+
; VFP9 Erratum 760019: It's potentially unsafe to overwrite the input
; operands, so mark the output as early clobber for VFPv2 on ARMv5 or
; earlier.
;; Multiplication insns
+(define_insn "mulhf3"
+ [(set
+ (match_operand:HF 0 "s_register_operand" "=w")
+ (mult:HF (match_operand:HF 1 "s_register_operand" "w")
+ (match_operand:HF 2 "s_register_operand" "w")))]
+ "TARGET_VFP_FP16INST"
+ "vmul.f16\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fmuls")]
+)
+
(define_insn "*mulsf3_vfp"
[(set (match_operand:SF 0 "s_register_operand" "=t")
(mult:SF (match_operand:SF 1 "s_register_operand" "t")
(set_attr "type" "fmuld")]
)
+(define_insn "*mulsf3neghf_vfp"
+ [(set (match_operand:HF 0 "s_register_operand" "=t")
+ (mult:HF (neg:HF (match_operand:HF 1 "s_register_operand" "t"))
+ (match_operand:HF 2 "s_register_operand" "t")))]
+ "TARGET_VFP_FP16INST && !flag_rounding_math"
+ "vnmul.f16\\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fmuls")]
+)
+
+(define_insn "*negmulhf3_vfp"
+ [(set (match_operand:HF 0 "s_register_operand" "=t")
+ (neg:HF (mult:HF (match_operand:HF 1 "s_register_operand" "t")
+ (match_operand:HF 2 "s_register_operand" "t"))))]
+ "TARGET_VFP_FP16INST"
+ "vnmul.f16\\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fmuls")]
+)
+
(define_insn "*mulsf3negsf_vfp"
[(set (match_operand:SF 0 "s_register_operand" "=t")
(mult:SF (neg:SF (match_operand:SF 1 "s_register_operand" "t"))
;; Multiply-accumulate insns
;; 0 = 1 * 2 + 0
+(define_insn "*mulsf3addhf_vfp"
+ [(set (match_operand:HF 0 "s_register_operand" "=t")
+ (plus:HF
+ (mult:HF (match_operand:HF 2 "s_register_operand" "t")
+ (match_operand:HF 3 "s_register_operand" "t"))
+ (match_operand:HF 1 "s_register_operand" "0")))]
+ "TARGET_VFP_FP16INST"
+ "vmla.f16\\t%0, %2, %3"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fmacs")]
+)
+
(define_insn "*mulsf3addsf_vfp"
[(set (match_operand:SF 0 "s_register_operand" "=t")
(plus:SF (mult:SF (match_operand:SF 2 "s_register_operand" "t")
)
;; 0 = 1 * 2 - 0
+(define_insn "*mulhf3subhf_vfp"
+ [(set (match_operand:HF 0 "s_register_operand" "=t")
+ (minus:HF (mult:HF (match_operand:HF 2 "s_register_operand" "t")
+ (match_operand:HF 3 "s_register_operand" "t"))
+ (match_operand:HF 1 "s_register_operand" "0")))]
+ "TARGET_VFP_FP16INST"
+ "vnmls.f16\\t%0, %2, %3"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fmacs")]
+)
+
(define_insn "*mulsf3subsf_vfp"
[(set (match_operand:SF 0 "s_register_operand" "=t")
(minus:SF (mult:SF (match_operand:SF 2 "s_register_operand" "t")
)
;; 0 = -(1 * 2) + 0
+(define_insn "*mulhf3neghfaddhf_vfp"
+ [(set (match_operand:HF 0 "s_register_operand" "=t")
+ (minus:HF (match_operand:HF 1 "s_register_operand" "0")
+ (mult:HF (match_operand:HF 2 "s_register_operand" "t")
+ (match_operand:HF 3 "s_register_operand" "t"))))]
+ "TARGET_VFP_FP16INST"
+ "vmls.f16\\t%0, %2, %3"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fmacs")]
+)
+
(define_insn "*mulsf3negsfaddsf_vfp"
[(set (match_operand:SF 0 "s_register_operand" "=t")
(minus:SF (match_operand:SF 1 "s_register_operand" "0")
;; 0 = -(1 * 2) - 0
+(define_insn "*mulhf3neghfsubhf_vfp"
+ [(set (match_operand:HF 0 "s_register_operand" "=t")
+ (minus:HF (mult:HF
+ (neg:HF (match_operand:HF 2 "s_register_operand" "t"))
+ (match_operand:HF 3 "s_register_operand" "t"))
+ (match_operand:HF 1 "s_register_operand" "0")))]
+ "TARGET_VFP_FP16INST"
+ "vnmla.f16\\t%0, %2, %3"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fmacs")]
+)
+
(define_insn "*mulsf3negsfsubsf_vfp"
[(set (match_operand:SF 0 "s_register_operand" "=t")
(minus:SF (mult:SF
;; Fused-multiply-accumulate
+(define_insn "fmahf4"
+ [(set (match_operand:HF 0 "register_operand" "=w")
+ (fma:HF
+ (match_operand:HF 1 "register_operand" "w")
+ (match_operand:HF 2 "register_operand" "w")
+ (match_operand:HF 3 "register_operand" "0")))]
+ "TARGET_VFP_FP16INST"
+ "vfma.f16\\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "ffmas")]
+)
+
+(define_expand "neon_vfmahf"
+ [(match_operand:HF 0 "s_register_operand")
+ (match_operand:HF 1 "s_register_operand")
+ (match_operand:HF 2 "s_register_operand")
+ (match_operand:HF 3 "s_register_operand")]
+ "TARGET_VFP_FP16INST"
+{
+ emit_insn (gen_fmahf4 (operands[0], operands[2], operands[3],
+ operands[1]));
+ DONE;
+})
+
(define_insn "fma<SDF:mode>4"
[(set (match_operand:SDF 0 "register_operand" "=<F_constraint>")
(fma:SDF (match_operand:SDF 1 "register_operand" "<F_constraint>")
(set_attr "type" "ffma<vfp_type>")]
)
+(define_insn "fmsubhf4_fp16"
+ [(set (match_operand:HF 0 "register_operand" "=w")
+ (fma:HF
+ (neg:HF (match_operand:HF 1 "register_operand" "w"))
+ (match_operand:HF 2 "register_operand" "w")
+ (match_operand:HF 3 "register_operand" "0")))]
+ "TARGET_VFP_FP16INST"
+ "vfms.f16\\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "ffmas")]
+)
+
+(define_expand "neon_vfmshf"
+ [(match_operand:HF 0 "s_register_operand")
+ (match_operand:HF 1 "s_register_operand")
+ (match_operand:HF 2 "s_register_operand")
+ (match_operand:HF 3 "s_register_operand")]
+ "TARGET_VFP_FP16INST"
+{
+ emit_insn (gen_fmsubhf4_fp16 (operands[0], operands[2], operands[3],
+ operands[1]));
+ DONE;
+})
+
(define_insn "*fmsub<SDF:mode>4"
[(set (match_operand:SDF 0 "register_operand" "=<F_constraint>")
(fma:SDF (neg:SDF (match_operand:SDF 1 "register_operand"
(set_attr "type" "ffma<vfp_type>")]
)
+(define_insn "*fnmsubhf4"
+ [(set (match_operand:HF 0 "register_operand" "=w")
+ (fma:HF (match_operand:HF 1 "register_operand" "w")
+ (match_operand:HF 2 "register_operand" "w")
+ (neg:HF (match_operand:HF 3 "register_operand" "0"))))]
+ "TARGET_VFP_FP16INST"
+ "vfnms.f16\\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "ffmas")]
+)
+
(define_insn "*fnmsub<SDF:mode>4"
[(set (match_operand:SDF 0 "register_operand" "=<F_constraint>")
(fma:SDF (match_operand:SDF 1 "register_operand" "<F_constraint>")
(set_attr "type" "ffma<vfp_type>")]
)
+(define_insn "*fnmaddhf4"
+ [(set (match_operand:HF 0 "register_operand" "=w")
+ (fma:HF (neg:HF (match_operand:HF 1 "register_operand" "w"))
+ (match_operand:HF 2 "register_operand" "w")
+ (neg:HF (match_operand:HF 3 "register_operand" "0"))))]
+ "TARGET_VFP_FP16INST"
+ "vfnma.f16\\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "ffmas")]
+)
+
(define_insn "*fnmadd<SDF:mode>4"
[(set (match_operand:SDF 0 "register_operand" "=<F_constraint>")
(fma:SDF (neg:SDF (match_operand:SDF 1 "register_operand"
;; Sqrt insns.
+(define_insn "neon_vsqrthf"
+ [(set (match_operand:HF 0 "s_register_operand" "=w")
+ (sqrt:HF (match_operand:HF 1 "s_register_operand" "w")))]
+ "TARGET_VFP_FP16INST"
+ "vsqrt.f16\t%0, %1"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fsqrts")]
+)
+
+(define_insn "neon_vrsqrtshf"
+ [(set
+ (match_operand:HF 0 "s_register_operand" "=w")
+ (unspec:HF [(match_operand:HF 1 "s_register_operand" "w")
+ (match_operand:HF 2 "s_register_operand" "w")]
+ UNSPEC_VRSQRTS))]
+ "TARGET_VFP_FP16INST"
+ "vrsqrts.f16\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "fsqrts")]
+)
+
; VFP9 Erratum 760019: It's potentially unsafe to overwrite the input
; operands, so mark the output as early clobber for VFPv2 on ARMv5 or
; earlier.
)
;; Fixed point to floating point conversions.
-(define_code_iterator FCVT [unsigned_float float])
-(define_code_attr FCVTI32typename [(unsigned_float "u32") (float "s32")])
-
(define_insn "*combine_vcvt_f32_<FCVTI32typename>"
[(set (match_operand:SF 0 "s_register_operand" "=t")
(mult:SF (FCVT:SF (match_operand:SI 1 "s_register_operand" "0"))
(set_attr "type" "f_cvtf2i")]
)
+;; FP16 conversions.
+(define_insn "neon_vcvth<sup>hf"
+ [(set (match_operand:HF 0 "s_register_operand" "=w")
+ (unspec:HF
+ [(match_operand:SI 1 "s_register_operand" "w")]
+ VCVTH_US))]
+ "TARGET_VFP_FP16INST"
+ "vcvt.f16.<sup>%#32\t%0, %1"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "f_cvti2f")]
+)
+
+(define_insn "neon_vcvth<sup>si"
+ [(set (match_operand:SI 0 "s_register_operand" "=w")
+ (unspec:SI
+ [(match_operand:HF 1 "s_register_operand" "w")]
+ VCVTH_US))]
+ "TARGET_VFP_FP16INST"
+ "vcvt.<sup>%#32.f16\t%0, %1"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "f_cvtf2i")]
+)
+
+;; The neon_vcvth<sup>_nhf patterns are used to generate the instruction for the
+;; vcvth_n_f16_<sup>32 arm_fp16 intrinsics. They are complicated by the
+;; hardware requirement that the source and destination registers are the same
+;; despite having different machine modes. The approach is to use a temporary
+;; register for the conversion and move that to the correct destination.
+
+;; Generate an unspec pattern for the intrinsic.
+(define_insn "neon_vcvth<sup>_nhf_unspec"
+ [(set
+ (match_operand:SI 0 "s_register_operand" "=w")
+ (unspec:SI
+ [(match_operand:SI 1 "s_register_operand" "0")
+ (match_operand:SI 2 "immediate_operand" "i")]
+ VCVT_HF_US_N))
+ (set
+ (match_operand:HF 3 "s_register_operand" "=w")
+ (float_truncate:HF (float:SF (match_dup 0))))]
+ "TARGET_VFP_FP16INST"
+{
+ neon_const_bounds (operands[2], 1, 33);
+ return "vcvt.f16.<sup>32\t%0, %0, %2\;vmov.f32\t%3, %0";
+}
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "f_cvti2f")]
+)
+
+;; Generate the instruction patterns needed for vcvth_n_f16_s32 neon intrinsics.
+(define_expand "neon_vcvth<sup>_nhf"
+ [(match_operand:HF 0 "s_register_operand")
+ (unspec:HF [(match_operand:SI 1 "s_register_operand")
+ (match_operand:SI 2 "immediate_operand")]
+ VCVT_HF_US_N)]
+"TARGET_VFP_FP16INST"
+{
+ rtx op1 = gen_reg_rtx (SImode);
+
+ neon_const_bounds (operands[2], 1, 33);
+
+ emit_move_insn (op1, operands[1]);
+ emit_insn (gen_neon_vcvth<sup>_nhf_unspec (op1, op1, operands[2],
+ operands[0]));
+ DONE;
+})
+
+;; The neon_vcvth<sup>_nsi patterns are used to generate the instruction for the
+;; vcvth_n_<sup>32_f16 arm_fp16 intrinsics. They have the same restrictions and
+;; are implemented in the same way as the neon_vcvth<sup>_nhf patterns.
+
+;; Generate an unspec pattern, constraining the registers.
+(define_insn "neon_vcvth<sup>_nsi_unspec"
+ [(set (match_operand:SI 0 "s_register_operand" "=w")
+ (unspec:SI
+ [(fix:SI
+ (fix:SF
+ (float_extend:SF
+ (match_operand:HF 1 "s_register_operand" "w"))))
+ (match_operand:SI 2 "immediate_operand" "i")]
+ VCVT_SI_US_N))]
+ "TARGET_VFP_FP16INST"
+{
+ neon_const_bounds (operands[2], 1, 33);
+ return "vmov.f32\t%0, %1\;vcvt.<sup>%#32.f16\t%0, %0, %2";
+}
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "f_cvtf2i")]
+)
+
+;; Generate the instruction patterns needed for vcvth_n_f16_s32 neon intrinsics.
+(define_expand "neon_vcvth<sup>_nsi"
+ [(match_operand:SI 0 "s_register_operand")
+ (unspec:SI
+ [(match_operand:HF 1 "s_register_operand")
+ (match_operand:SI 2 "immediate_operand")]
+ VCVT_SI_US_N)]
+ "TARGET_VFP_FP16INST"
+{
+ rtx op1 = gen_reg_rtx (SImode);
+
+ neon_const_bounds (operands[2], 1, 33);
+ emit_insn (gen_neon_vcvth<sup>_nsi_unspec (op1, operands[1], operands[2]));
+ emit_move_insn (operands[0], op1);
+ DONE;
+})
+
+(define_insn "neon_vcvt<vcvth_op>h<sup>si"
+ [(set
+ (match_operand:SI 0 "s_register_operand" "=w")
+ (unspec:SI
+ [(match_operand:HF 1 "s_register_operand" "w")]
+ VCVT_HF_US))]
+ "TARGET_VFP_FP16INST"
+ "vcvt<vcvth_op>.<sup>%#32.f16\t%0, %1"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "f_cvtf2i")]
+)
+
;; Store multiple insn used in function prologue.
(define_insn "*push_multi_vfp"
[(match_parallel 2 "multi_register_push"
)
;; Scalar forms for the IEEE-754 fmax()/fmin() functions
+
+(define_insn "neon_<fmaxmin_op>hf"
+ [(set
+ (match_operand:HF 0 "s_register_operand" "=w")
+ (unspec:HF
+ [(match_operand:HF 1 "s_register_operand" "w")
+ (match_operand:HF 2 "s_register_operand" "w")]
+ VMAXMINFNM))]
+ "TARGET_VFP_FP16INST"
+ "<fmaxmin_op>.f16\t%0, %1, %2"
+ [(set_attr "conds" "unconditional")
+ (set_attr "type" "f_minmaxs")]
+)
+
(define_insn "<fmaxmin><mode>3"
[(set (match_operand:SDF 0 "s_register_operand" "=<F_constraint>")
(unspec:SDF [(match_operand:SDF 1 "s_register_operand" "<F_constraint>")
--- /dev/null
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_2a_fp16_scalar_ok } */
+/* { dg-options "-O2 -ffast-math" } */
+/* { dg-add-options arm_v8_2a_fp16_scalar } */
+
+/* Test instructions generated for half-precision arithmetic. */
+
+typedef __fp16 float16_t;
+typedef __simd64_float16_t float16x4_t;
+typedef __simd128_float16_t float16x8_t;
+
+float16_t
+fp16_abs (float16_t a)
+{
+ return (a < 0) ? -a : a;
+}
+
+#define TEST_UNOP(NAME, OPERATOR, TY) \
+ TY test_##NAME##_##TY (TY a) \
+ { \
+ return OPERATOR (a); \
+ }
+
+#define TEST_BINOP(NAME, OPERATOR, TY) \
+ TY test_##NAME##_##TY (TY a, TY b) \
+ { \
+ return a OPERATOR b; \
+ }
+
+#define TEST_CMP(NAME, OPERATOR, RTY, TY) \
+ RTY test_##NAME##_##TY (TY a, TY b) \
+ { \
+ return a OPERATOR b; \
+ }
+
+/* Scalars. */
+
+TEST_UNOP (neg, -, float16_t)
+TEST_UNOP (abs, fp16_abs, float16_t)
+
+TEST_BINOP (add, +, float16_t)
+TEST_BINOP (sub, -, float16_t)
+TEST_BINOP (mult, *, float16_t)
+TEST_BINOP (div, /, float16_t)
+
+TEST_CMP (equal, ==, int, float16_t)
+TEST_CMP (unequal, !=, int, float16_t)
+TEST_CMP (lessthan, <, int, float16_t)
+TEST_CMP (greaterthan, >, int, float16_t)
+TEST_CMP (lessthanequal, <=, int, float16_t)
+TEST_CMP (greaterthanqual, >=, int, float16_t)
+
+/* { dg-final { scan-assembler-times {vneg\.f16\ts[0-9]+, s[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {vabs\.f16\ts[0-9]+, s[0-9]+} 2 } } */
+
+/* { dg-final { scan-assembler-times {vadd\.f16\ts[0-9]+, s[0-9]+, s[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {vsub\.f16\ts[0-9]+, s[0-9]+, s[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {vmul\.f16\ts[0-9]+, s[0-9]+, s[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {vdiv\.f16\ts[0-9]+, s[0-9]+, s[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {vcmp\.f32\ts[0-9]+, s[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {vcmpe\.f32\ts[0-9]+, s[0-9]+} 4 } } */
+
+/* { dg-final { scan-assembler-not {vadd\.f32} } } */
+/* { dg-final { scan-assembler-not {vsub\.f32} } } */
+/* { dg-final { scan-assembler-not {vmul\.f32} } } */
+/* { dg-final { scan-assembler-not {vdiv\.f32} } } */
+/* { dg-final { scan-assembler-not {vcmp\.f16} } } */
+/* { dg-final { scan-assembler-not {vcmpe\.f16} } } */