Hi! On Tue, Nov 12, 2019 at 06:41:07PM +0800, Kewen.Lin wrote: > +;; code iterators and attributes for vector FP comparison operators: > +(define_code_iterator vector_fp_comparison_operator [lt le ne > + ungt unge unlt unle])
Let's indent that differently? (define_code_iterator vector_fp_comparison_operator [lt le ne ungt unge unlt unle]) is nice I think. > +; There are 14 possible vector FP comparison operators, gt and eq of them > have > +; been expanded above, so just support 12 remaining operators here. > > +; 0. For ge: (Don't number comments please). > +(define_expand "vector_ge<mode>" > + [(set (match_operand:VEC_F 0 "vlogical_operand") > + (ge:VEC_F (match_operand:VEC_F 1 "vlogical_operand") > + (match_operand:VEC_F 2 "vlogical_operand")))] > "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)" > + "") This already exists? Line 764 in vector.md? > +; 1. For lt/le/ne/ungt/unge/unlt/unle: > +; lt(a,b) = gt(b,a) > +; le(a,b) = ge(b,a) > +; unge(a,b) = ~lt(a,b) > +; unle(a,b) = ~gt(a,b) > +; ne(a,b) = ~eq(a,b) > +; ungt(a,b) = ~le(a,b) > +; unlt(a,b) = ~ge(a,b) > +(define_insn_and_split "vector_<code><mode>" > [(set (match_operand:VEC_F 0 "vfloat_operand") > + (vector_fp_comparison_operator:VEC_F > + (match_operand:VEC_F 1 "vfloat_operand") > + (match_operand:VEC_F 2 "vfloat_operand")))] > "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)" > "#" > + "can_create_pseudo_p ()" > + [(pc)] > { > + enum rtx_code cond = <CODE>; > + rtx res = gen_reg_rtx (<MODE>mode); > + bool need_invert = false; > + switch (cond) > + { > + case LT: > + case LE: > + cond = swap_condition (cond); > + std::swap (operands[1], operands[2]); > + break; > + case UNLE: > + case UNLT: > + case NE: > + case UNGE: > + case UNGT: > + cond = reverse_condition_maybe_unordered (cond); > + need_invert = true; > + break; > + default: > + gcc_unreachable (); > + } > + > + rtx comp = gen_rtx_fmt_ee (cond, <MODE>mode, operands[1], operands[2]); > + emit_insn (gen_rtx_SET (res, comp)); > + > + if (need_invert) > + emit_insn (gen_one_cmpl<mode>2 (res, res)); > + > + emit_insn (gen_rtx_SET (operands[0], res)); > }) Does this work for (say) ungt? I would do two switch statements: the first only to do the invert, and then the second to do the swap (with the modified cond!) So: { enum rtx_code cond = <CODE>; bool need_invert = false; if (cond == UNLE || cond == UNLT || cond == NE || cond == UNGE || cond == UNGT) { cond = reverse_condition_maybe_unordered (cond); need_invert = true; } if (cond == LT || cond == LE) { cond = swap_condition (cond); std::swap (operands[1], operands[2]); } rtx comp = gen_rtx_fmt_ee (cond, <MODE>mode, operands[1], operands[2]); if (need_invert) { rtx res = gen_reg_rtx (<MODE>mode); emit_insn (gen_rtx_SET (res, comp)); emit_insn (gen_one_cmpl<mode>2 (operands[0], res)); } else emit_insn (gen_rtx_SET (operands[0], comp)); }) > +; 2. For ltgt/uneq/ordered/unordered: > +; ltgt: gt(a,b) | gt(b,a) > +; uneq: ~gt(a,b) & ~gt(b,a) > +; ordered: ge(a,b) | ge(b,a) > +; unordered: ~ge(a,b) & ~ge(b,a) You could write that as ~(ge(a,b) | ge(b,a)) which may show the structure better? > +(define_insn_and_split "vector_<code><mode>" > [(set (match_operand:VEC_F 0 "vfloat_operand") > + (vector_fp_extra_comparison_operator:VEC_F > + (match_operand:VEC_F 1 "vfloat_operand") > + (match_operand:VEC_F 2 "vfloat_operand")))] > "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)" > "#" > + "can_create_pseudo_p ()" This should be "&& can_create_pseudo ()". Also, can_create_pseudo in the split condition can fail, in theory anyway. It should be part of the insn condition, instead, and even then it can fail: after the last split pass, but before reload. such an insn can in principle be created, and then it sill be never split. In this case, maybe you should add a scratch register; in the previous case, you can reuse operands[0] for res instead of making a new reg for it, if !can_create_pseudo (). > { > + enum rtx_code cond = <CODE>; > + rtx res1 = gen_reg_rtx (<MODE>mode); > + rtx res2 = gen_reg_rtx (<MODE>mode); > + bool need_invert = false; > + switch (cond) > + { > + case UNEQ: > + need_invert = true; > + /* Fall through. */ > + case LTGT: > + cond = GT; > + break; > + case UNORDERED: > + need_invert = true; > + /* Fall through. */ > + case ORDERED: > + cond = GE; > + break; > + default: > + gcc_unreachable (); > + } > + > + rtx comp1 = gen_rtx_fmt_ee (cond, <MODE>mode, operands[1], operands[2]); > + emit_insn (gen_rtx_SET (res1, comp1)); > + rtx comp2 = gen_rtx_fmt_ee (cond, <MODE>mode, operands[2], operands[1]); > + emit_insn (gen_rtx_SET (res2, comp2)); > + > + emit_insn (gen_ior<mode>3 (res1, res1, res2)); > + > + if (need_invert) > + emit_insn (gen_one_cmpl<mode>2 (res1, res1)); > + > + emit_insn (gen_rtx_SET (operands[0], res1)); > }) You can do this similarly: { enum rtx_code cond = <CODE>; bool need_invert = false; if (cond == UNORDERED || cond == UNEQ) { cond = reverse_condition_maybe_unordered (cond); need_invert = true; } switch (cond) { case LTGT: cond = GT; break; case ORDERED: cond = GE; break; default: gcc_unreachable (); } rtx comp1 = gen_rtx_fmt_ee (cond, <MODE>mode, operands[1], operands[2]); rtx res1 = gen_reg_rtx (<MODE>mode); emit_insn (gen_rtx_SET (res1, comp1)); rtx comp2 = gen_rtx_fmt_ee (cond, <MODE>mode, operands[2], operands[1]); rtx res2 = gen_reg_rtx (<MODE>mode); emit_insn (gen_rtx_SET (res2, comp2)); if (need_invert) { rtx comp3 = gen_rtx_fmt_ee (IOR, <MODE>mode, res1, res2); rtx comp4 = gen_rtx_fmt_e (NOT, <MODE>mode, comp3); emit_insn (gen_rtx_SET (operands[0], comp4)); } else emit_insn (gen_ior<mode>3 (operands[0], res1, res2)); }) (the result of a split does not get combine etc. optimisations anymore, so you have to generate pretty much ideal code directly). HTH, sorry for the late reply, Segher