diff options
author | ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-04-23 16:19:26 +0000 |
---|---|---|
committer | ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-04-23 16:19:26 +0000 |
commit | 996c516f7eaa15c85fd72d3be15acf4a927c0801 (patch) | |
tree | 6dcaaaa4874067350a9fb8c452f51fccac53dd6e /gcc/config/arm/neon.md | |
parent | 61ba0ff6b1a773d8da32f351403b10a8ba47206f (diff) | |
download | gcc-996c516f7eaa15c85fd72d3be15acf4a927c0801.tar.gz |
[ARM] Rewrite vc<cond> NEON patterns to use RTL operations rather than UNSPECs
* config/arm/iterators.md (GTGE, GTUGEU, COMPARISONS): New code
iterators.
(cmp_op, cmp_type): New code attributes.
(NEON_VCMP, NEON_VACMP): New int iterators.
(cmp_op_unsp): New int attribute.
* config/arm/neon.md (neon_vc<cmp_op><mode>): New define_expand.
(neon_vceq<mode>): Delete.
(neon_vc<cmp_op><mode>_insn): New pattern.
(neon_vc<cmp_op_unsp><mode>_insn_unspec): Likewise.
(neon_vcgeu<mode>): Delete.
(neon_vcle<mode>): Likewise.
(neon_vclt<mode>: Likewise.
(neon_vcage<mode>): Likewise.
(neon_vcagt<mode>): Likewise.
(neon_vca<cmp_op><mode>): New define_expand.
(neon_vca<cmp_op><mode>_insn): New pattern.
(neon_vca<cmp_op_unsp><mode>_insn_unspec): Likewise.
* gcc.target/arm/neon/pr51534.c: Update vcg* scan-assembly patterns
to look for vcl* where appropriate.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222379 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/arm/neon.md')
-rw-r--r-- | gcc/config/arm/neon.md | 204 |
1 files changed, 105 insertions, 99 deletions
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md index 63c327ec68c..445df2ad0bd 100644 --- a/gcc/config/arm/neon.md +++ b/gcc/config/arm/neon.md @@ -2200,134 +2200,140 @@ [(set_attr "type" "neon_sub_halve_narrow_q")] ) -(define_insn "neon_vceq<mode>" - [(set (match_operand:<V_cmp_result> 0 "s_register_operand" "=w,w") - (unspec:<V_cmp_result> - [(match_operand:VDQW 1 "s_register_operand" "w,w") - (match_operand:VDQW 2 "reg_or_zero_operand" "w,Dz")] - UNSPEC_VCEQ))] +;; These may expand to an UNSPEC pattern when a floating point mode is used +;; without unsafe math optimizations. +(define_expand "neon_vc<cmp_op><mode>" + [(match_operand:<V_cmp_result> 0 "s_register_operand" "=w,w") + (neg:<V_cmp_result> + (COMPARISONS:VDQW (match_operand:VDQW 1 "s_register_operand" "w,w") + (match_operand:VDQW 2 "reg_or_zero_operand" "w,Dz")))] "TARGET_NEON" - "@ - vceq.<V_if_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2 - vceq.<V_if_elem>\t%<V_reg>0, %<V_reg>1, #0" - [(set (attr "type") - (if_then_else (match_test "<Is_float_mode>") - (const_string "neon_fp_compare_s<q>") - (if_then_else (match_operand 2 "zero_operand") - (const_string "neon_compare_zero<q>") - (const_string "neon_compare<q>"))))] + { + /* For FP comparisons use UNSPECS unless -funsafe-math-optimizations + are enabled. */ + if (GET_MODE_CLASS (<MODE>mode) == MODE_VECTOR_FLOAT + && !flag_unsafe_math_optimizations) + { + /* We don't just emit a gen_neon_vc<cmp_op><mode>_insn_unspec because + we define gen_neon_vceq<mode>_insn_unspec only for float modes + whereas this expander iterates over the integer modes as well, + but we will never expand to UNSPECs for the integer comparisons. */ + switch (<MODE>mode) + { + case V2SFmode: + emit_insn (gen_neon_vc<cmp_op>v2sf_insn_unspec (operands[0], + operands[1], + operands[2])); + break; + case V4SFmode: + emit_insn (gen_neon_vc<cmp_op>v4sf_insn_unspec (operands[0], + operands[1], + operands[2])); + break; + default: + gcc_unreachable (); + } + } + else + emit_insn (gen_neon_vc<cmp_op><mode>_insn (operands[0], + operands[1], + operands[2])); + DONE; + } ) -(define_insn "neon_vcge<mode>" +(define_insn "neon_vc<cmp_op><mode>_insn" [(set (match_operand:<V_cmp_result> 0 "s_register_operand" "=w,w") - (unspec:<V_cmp_result> - [(match_operand:VDQW 1 "s_register_operand" "w,w") - (match_operand:VDQW 2 "reg_or_zero_operand" "w,Dz")] - UNSPEC_VCGE))] - "TARGET_NEON" - "@ - vcge.<V_s_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2 - vcge.<V_s_elem>\t%<V_reg>0, %<V_reg>1, #0" + (neg:<V_cmp_result> + (COMPARISONS:<V_cmp_result> + (match_operand:VDQW 1 "s_register_operand" "w,w") + (match_operand:VDQW 2 "reg_or_zero_operand" "w,Dz"))))] + "TARGET_NEON && !(GET_MODE_CLASS (<MODE>mode) == MODE_VECTOR_FLOAT + && !flag_unsafe_math_optimizations)" + { + char pattern[100]; + sprintf (pattern, "vc<cmp_op>.%s%%#<V_sz_elem>\t%%<V_reg>0," + " %%<V_reg>1, %s", + GET_MODE_CLASS (<MODE>mode) == MODE_VECTOR_FLOAT + ? "f" : "<cmp_type>", + which_alternative == 0 + ? "%<V_reg>2" : "#0"); + output_asm_insn (pattern, operands); + return ""; + } [(set (attr "type") - (if_then_else (match_test "<Is_float_mode>") - (const_string "neon_fp_compare_s<q>") - (if_then_else (match_operand 2 "zero_operand") + (if_then_else (match_operand 2 "zero_operand") (const_string "neon_compare_zero<q>") - (const_string "neon_compare<q>"))))] -) - -(define_insn "neon_vcgeu<mode>" - [(set (match_operand:<V_cmp_result> 0 "s_register_operand" "=w") - (unspec:<V_cmp_result> - [(match_operand:VDQIW 1 "s_register_operand" "w") - (match_operand:VDQIW 2 "s_register_operand" "w")] - UNSPEC_VCGEU))] - "TARGET_NEON" - "vcge.u%#<V_sz_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2" - [(set_attr "type" "neon_compare<q>")] + (const_string "neon_compare<q>")))] ) -(define_insn "neon_vcgt<mode>" +(define_insn "neon_vc<cmp_op_unsp><mode>_insn_unspec" [(set (match_operand:<V_cmp_result> 0 "s_register_operand" "=w,w") (unspec:<V_cmp_result> - [(match_operand:VDQW 1 "s_register_operand" "w,w") - (match_operand:VDQW 2 "reg_or_zero_operand" "w,Dz")] - UNSPEC_VCGT))] + [(match_operand:VCVTF 1 "s_register_operand" "w,w") + (match_operand:VCVTF 2 "reg_or_zero_operand" "w,Dz")] + NEON_VCMP))] "TARGET_NEON" - "@ - vcgt.<V_s_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2 - vcgt.<V_s_elem>\t%<V_reg>0, %<V_reg>1, #0" - [(set (attr "type") - (if_then_else (match_test "<Is_float_mode>") - (const_string "neon_fp_compare_s<q>") - (if_then_else (match_operand 2 "zero_operand") - (const_string "neon_compare_zero<q>") - (const_string "neon_compare<q>"))))] + { + char pattern[100]; + sprintf (pattern, "vc<cmp_op_unsp>.f%%#<V_sz_elem>\t%%<V_reg>0," + " %%<V_reg>1, %s", + which_alternative == 0 + ? "%<V_reg>2" : "#0"); + output_asm_insn (pattern, operands); + return ""; +} + [(set_attr "type" "neon_fp_compare_s<q>")] ) -(define_insn "neon_vcgtu<mode>" +(define_insn "neon_vc<cmp_op>u<mode>" [(set (match_operand:<V_cmp_result> 0 "s_register_operand" "=w") - (unspec:<V_cmp_result> - [(match_operand:VDQIW 1 "s_register_operand" "w") - (match_operand:VDQIW 2 "s_register_operand" "w")] - UNSPEC_VCGTU))] + (neg:<V_cmp_result> + (GTUGEU:<V_cmp_result> + (match_operand:VDQIW 1 "s_register_operand" "w") + (match_operand:VDQIW 2 "s_register_operand" "w"))))] "TARGET_NEON" - "vcgt.u%#<V_sz_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2" + "vc<cmp_op>.u%#<V_sz_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2" [(set_attr "type" "neon_compare<q>")] ) -;; VCLE and VCLT only support comparisons with immediate zero (register -;; variants are VCGE and VCGT with operands reversed). - -(define_insn "neon_vcle<mode>" - [(set (match_operand:<V_cmp_result> 0 "s_register_operand" "=w") - (unspec:<V_cmp_result> - [(match_operand:VDQW 1 "s_register_operand" "w") - (match_operand:VDQW 2 "zero_operand" "Dz")] - UNSPEC_VCLE))] +(define_expand "neon_vca<cmp_op><mode>" + [(set (match_operand:<V_cmp_result> 0 "s_register_operand") + (neg:<V_cmp_result> + (GTGE:<V_cmp_result> + (abs:VCVTF (match_operand:VCVTF 1 "s_register_operand")) + (abs:VCVTF (match_operand:VCVTF 2 "s_register_operand")))))] "TARGET_NEON" - "vcle.<V_s_elem>\t%<V_reg>0, %<V_reg>1, #0" - [(set (attr "type") - (if_then_else (match_test "<Is_float_mode>") - (const_string "neon_fp_compare_s<q>") - (if_then_else (match_operand 2 "zero_operand") - (const_string "neon_compare_zero<q>") - (const_string "neon_compare<q>"))))] -) - -(define_insn "neon_vclt<mode>" - [(set (match_operand:<V_cmp_result> 0 "s_register_operand" "=w") - (unspec:<V_cmp_result> - [(match_operand:VDQW 1 "s_register_operand" "w") - (match_operand:VDQW 2 "zero_operand" "Dz")] - UNSPEC_VCLT))] - "TARGET_NEON" - "vclt.<V_s_elem>\t%<V_reg>0, %<V_reg>1, #0" - [(set (attr "type") - (if_then_else (match_test "<Is_float_mode>") - (const_string "neon_fp_compare_s<q>") - (if_then_else (match_operand 2 "zero_operand") - (const_string "neon_compare_zero<q>") - (const_string "neon_compare<q>"))))] + { + if (flag_unsafe_math_optimizations) + emit_insn (gen_neon_vca<cmp_op><mode>_insn (operands[0], operands[1], + operands[2])); + else + emit_insn (gen_neon_vca<cmp_op><mode>_insn_unspec (operands[0], + operands[1], + operands[2])); + DONE; + } ) -(define_insn "neon_vcage<mode>" +(define_insn "neon_vca<cmp_op><mode>_insn" [(set (match_operand:<V_cmp_result> 0 "s_register_operand" "=w") - (unspec:<V_cmp_result> [(match_operand:VCVTF 1 "s_register_operand" "w") - (match_operand:VCVTF 2 "s_register_operand" "w")] - UNSPEC_VCAGE))] - "TARGET_NEON" - "vacge.<V_if_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2" + (neg:<V_cmp_result> + (GTGE:<V_cmp_result> + (abs:VCVTF (match_operand:VCVTF 1 "s_register_operand" "w")) + (abs:VCVTF (match_operand:VCVTF 2 "s_register_operand" "w")))))] + "TARGET_NEON && flag_unsafe_math_optimizations" + "vac<cmp_op>.<V_if_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2" [(set_attr "type" "neon_fp_compare_s<q>")] ) -(define_insn "neon_vcagt<mode>" +(define_insn "neon_vca<cmp_op_unsp><mode>_insn_unspec" [(set (match_operand:<V_cmp_result> 0 "s_register_operand" "=w") (unspec:<V_cmp_result> [(match_operand:VCVTF 1 "s_register_operand" "w") (match_operand:VCVTF 2 "s_register_operand" "w")] - UNSPEC_VCAGT))] + NEON_VACMP))] "TARGET_NEON" - "vacgt.<V_if_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2" + "vac<cmp_op_unsp>.<V_if_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2" [(set_attr "type" "neon_fp_compare_s<q>")] ) |