From f35c297f8d42500060a2ca323af66c3aedea3334 Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Mon, 25 Mar 2013 13:48:06 +0000 Subject: [PATCH] re PR target/56720 (ICE when expanding vcond with floating point unordered comparisons) 2013-03-25 Kyrylo Tkachov PR target/56720 * config/arm/iterators.md (v_cmp_result): New mode attribute. * config/arm/neon.md (vcond): Handle unordered cases. 2013-03-25 Kyrylo Tkachov PR target/56720 * gcc.target/arm/neon-vcond-gt.c: New test. * gcc.target/arm/neon-vcond-ltgt.c: Likewise. * gcc.target/arm/neon-vcond-unordered.c: Likewise. From-SVN: r197040 --- gcc/ChangeLog | 5 ++ gcc/config/arm/iterators.md | 6 ++ gcc/config/arm/neon.md | 150 +++++++++++++++++++++++++----------- gcc/testsuite/ChangeLog | 6 ++ 4 files changed, 124 insertions(+), 43 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3db3f1d36d3..491937cb248 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2013-03-25 Kyrylo Tkachov + PR target/56720 + * config/arm/iterators.md (v_cmp_result): New mode attribute. + * config/arm/neon.md (vcond): Handle unordered cases. + 2013-03-25 Richard Biener PR tree-optimization/56689 diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index 252f18b40a8..b3ad42b376f 100644 --- a/gcc/config/arm/iterators.md +++ b/gcc/config/arm/iterators.md @@ -314,6 +314,12 @@ (V2SF "V2SI") (V4SF "V4SI") (DI "DI") (V2DI "V2DI")]) +(define_mode_attr v_cmp_result [(V8QI "v8qi") (V16QI "v16qi") + (V4HI "v4hi") (V8HI "v8hi") + (V2SI "v2si") (V4SI "v4si") + (DI "di") (V2DI "v2di") + (V2SF "v2si") (V4SF "v4si")]) + ;; Get element type from double-width mode, for operations where we ;; don't care about signedness. (define_mode_attr V_if_elem [(V8QI "i8") (V16QI "i8") diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md index 153475202d6..d7c2cb36949 100644 --- a/gcc/config/arm/neon.md +++ b/gcc/config/arm/neon.md @@ -1721,80 +1721,144 @@ (define_expand "vcond" [(set (match_operand:VDQW 0 "s_register_operand" "") (if_then_else:VDQW - (match_operator 3 "arm_comparison_operator" + (match_operator 3 "comparison_operator" [(match_operand:VDQW 4 "s_register_operand" "") (match_operand:VDQW 5 "nonmemory_operand" "")]) (match_operand:VDQW 1 "s_register_operand" "") (match_operand:VDQW 2 "s_register_operand" "")))] "TARGET_NEON && (! || flag_unsafe_math_optimizations)" { - rtx mask; - int inverse = 0, immediate_zero = 0; - /* See the description of "magic" bits in the 'T' case of - arm_print_operand. */ HOST_WIDE_INT magic_word = (mode == V2SFmode || mode == V4SFmode) ? 3 : 1; rtx magic_rtx = GEN_INT (magic_word); - - mask = gen_reg_rtx (mode); - - if (operands[5] == CONST0_RTX (mode)) - immediate_zero = 1; - else if (!REG_P (operands[5])) - operands[5] = force_reg (mode, operands[5]); - + int inverse = 0; + int swap_bsl_operands = 0; + rtx mask = gen_reg_rtx (mode); + rtx tmp = gen_reg_rtx (mode); + + rtx (*base_comparison) (rtx, rtx, rtx, rtx); + rtx (*complimentary_comparison) (rtx, rtx, rtx, rtx); + switch (GET_CODE (operands[3])) { case GE: - emit_insn (gen_neon_vcge (mask, operands[4], operands[5], - magic_rtx)); + case LE: + case EQ: + if (!REG_P (operands[5]) + && (operands[5] != CONST0_RTX (mode))) + operands[5] = force_reg (mode, operands[5]); break; - + default: + if (!REG_P (operands[5])) + operands[5] = force_reg (mode, operands[5]); + } + + switch (GET_CODE (operands[3])) + { + case LT: + case UNLT: + inverse = 1; + /* Fall through. */ + case GE: + case UNGE: + case ORDERED: + case UNORDERED: + base_comparison = gen_neon_vcge; + complimentary_comparison = gen_neon_vcgt; + break; + case LE: + case UNLE: + inverse = 1; + /* Fall through. */ case GT: - emit_insn (gen_neon_vcgt (mask, operands[4], operands[5], - magic_rtx)); + case UNGT: + base_comparison = gen_neon_vcgt; + complimentary_comparison = gen_neon_vcge; break; - case EQ: - emit_insn (gen_neon_vceq (mask, operands[4], operands[5], - magic_rtx)); + case NE: + case UNEQ: + base_comparison = gen_neon_vceq; + complimentary_comparison = gen_neon_vceq; break; - + default: + gcc_unreachable (); + } + + switch (GET_CODE (operands[3])) + { + case LT: case LE: - if (immediate_zero) - emit_insn (gen_neon_vcle (mask, operands[4], operands[5], - magic_rtx)); + case GT: + case GE: + case EQ: + /* The easy case. Here we emit one of vcge, vcgt or vceq. + As a LT b <=> b GE a && a LE b <=> b GT a. Our transformations are: + a GE b -> a GE b + a GT b -> a GT b + a LE b -> b GE a + a LT b -> b GT a + a EQ b -> a EQ b */ + + if (!inverse) + emit_insn (base_comparison (mask, operands[4], operands[5], magic_rtx)); else - emit_insn (gen_neon_vcge (mask, operands[5], operands[4], - magic_rtx)); + emit_insn (complimentary_comparison (mask, operands[5], operands[4], magic_rtx)); break; - - case LT: - if (immediate_zero) - emit_insn (gen_neon_vclt (mask, operands[4], operands[5], - magic_rtx)); + case UNLT: + case UNLE: + case UNGT: + case UNGE: + case NE: + /* Vector compare returns false for lanes which are unordered, so if we use + the inverse of the comparison we actually want to emit, then + swap the operands to BSL, we will end up with the correct result. + Note that a NE NaN and NaN NE b are true for all a, b. + + Our transformations are: + a GE b -> !(b GT a) + a GT b -> !(b GE a) + a LE b -> !(a GT b) + a LT b -> !(a GE b) + a NE b -> !(a EQ b) */ + + if (inverse) + emit_insn (base_comparison (mask, operands[4], operands[5], magic_rtx)); else - emit_insn (gen_neon_vcgt (mask, operands[5], operands[4], - magic_rtx)); + emit_insn (complimentary_comparison (mask, operands[5], operands[4], magic_rtx)); + + swap_bsl_operands = 1; break; - - case NE: - emit_insn (gen_neon_vceq (mask, operands[4], operands[5], - magic_rtx)); - inverse = 1; + case UNEQ: + /* We check (a > b || b > a). combining these comparisons give us + true iff !(a != b && a ORDERED b), swapping the operands to BSL + will then give us (a == b || a UNORDERED b) as intended. */ + + emit_insn (gen_neon_vcgt (mask, operands[4], operands[5], magic_rtx)); + emit_insn (gen_neon_vcgt (tmp, operands[5], operands[4], magic_rtx)); + emit_insn (gen_ior3 (mask, mask, tmp)); + swap_bsl_operands = 1; + break; + case UNORDERED: + /* Operands are ORDERED iff (a > b || b >= a). + Swapping the operands to BSL will give the UNORDERED case. */ + swap_bsl_operands = 1; + /* Fall through. */ + case ORDERED: + emit_insn (gen_neon_vcgt (tmp, operands[4], operands[5], magic_rtx)); + emit_insn (gen_neon_vcge (mask, operands[5], operands[4], magic_rtx)); + emit_insn (gen_ior3 (mask, mask, tmp)); break; - default: gcc_unreachable (); } - - if (inverse) + + if (swap_bsl_operands) emit_insn (gen_neon_vbsl (operands[0], mask, operands[2], operands[1])); else emit_insn (gen_neon_vbsl (operands[0], mask, operands[1], operands[2])); - DONE; }) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2aad75a8e34..7e1cd5b0d8f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2013-03-25 Kyrylo Tkachov + PR target/56720 + * gcc.target/arm/neon-vcond-gt.c: New test. + * gcc.target/arm/neon-vcond-ltgt.c: Likewise. + * gcc.target/arm/neon-vcond-unordered.c: Likewise. + 2013-03-25 Richard Biener PR tree-optimization/56689 -- 2.30.2