The rtl description of signed/unsigned overflow from subtract was fine, as far as it goes -- we have CC_Cmode and CC_Vmode that indicate that only those particular bits are valid.
However, it's not clear how to extend that description to handle signed comparison, where N == V (GE) N != V (LT) are the only valid bits. Using an UNSPEC means that we can unify all 3 usages without fear that combine will try to infer anything from the rtl. It also means we need far fewer variants when various inputs have constants propagated in, and the rtl folds. Accept -1 for the second input by using ADCS. * config/aarch64/aarch64.md (UNSPEC_SBCS): New. (cmp<GPI>3_carryin): New expander. (sub<GPI>3_carryin_cmp): New expander. (*cmp<GPI>3_carryin): New pattern. (*cmp<GPI>3_carryin_0): New pattern. (*sub<GPI>3_carryin_cmp): New pattern. (*sub<GPI>3_carryin_cmp_0): New pattern. (subvti4, usubvti4, negvti3): Use subdi3_carryin_cmp. (negvdi_carryinV): Remove. (usub<GPI>3_carryinC): Remove. (*usub<GPI>3_carryinC): Remove. (*usub<GPI>3_carryinC_z1): Remove. (*usub<GPI>3_carryinC_z2): Remove. (sub<GPI>3_carryinV): Remove. (*sub<GPI>3_carryinV): Remove. (*sub<GPI>3_carryinV_z2): Remove. * config/aarch64/predicates.md (aarch64_reg_zero_minus1): New. --- gcc/config/aarch64/aarch64.md | 217 +++++++++++++------------------ gcc/config/aarch64/predicates.md | 7 + 2 files changed, 94 insertions(+), 130 deletions(-) diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 532c114a42e..564dea390be 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -281,6 +281,7 @@ UNSPEC_GEN_TAG_RND ; Generate a random 4-bit MTE tag. UNSPEC_TAG_SPACE ; Translate address to MTE tag address space. UNSPEC_LD1RO + UNSPEC_SBCS ]) (define_c_enum "unspecv" [ @@ -2942,7 +2943,7 @@ aarch64_expand_addsubti (operands[0], operands[1], operands[2], CODE_FOR_subvdi_insn, CODE_FOR_subdi3_compare1, - CODE_FOR_subdi3_carryinV); + CODE_FOR_subdi3_carryin_cmp); aarch64_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]); DONE; }) @@ -2957,7 +2958,7 @@ aarch64_expand_addsubti (operands[0], operands[1], operands[2], CODE_FOR_subdi3_compare1, CODE_FOR_subdi3_compare1, - CODE_FOR_usubdi3_carryinC); + CODE_FOR_subdi3_carryin_cmp); aarch64_gen_unlikely_cbranch (LTU, CCmode, operands[3]); DONE; }) @@ -2968,12 +2969,14 @@ (label_ref (match_operand 2 "" ""))] "" { - emit_insn (gen_negdi_carryout (gen_lowpart (DImode, operands[0]), - gen_lowpart (DImode, operands[1]))); - emit_insn (gen_negvdi_carryinV (gen_highpart (DImode, operands[0]), - gen_highpart (DImode, operands[1]))); - aarch64_gen_unlikely_cbranch (NE, CC_Vmode, operands[2]); + rtx op0l = gen_lowpart (DImode, operands[0]); + rtx op1l = gen_lowpart (DImode, operands[1]); + rtx op0h = gen_highpart (DImode, operands[0]); + rtx op1h = gen_highpart (DImode, operands[1]); + emit_insn (gen_negdi_carryout (op0l, op1l)); + emit_insn (gen_subdi3_carryin_cmp (op0h, const0_rtx, op1h)); + aarch64_gen_unlikely_cbranch (NE, CC_Vmode, operands[2]); DONE; } ) @@ -2989,23 +2992,6 @@ [(set_attr "type" "alus_sreg")] ) -(define_insn "negvdi_carryinV" - [(set (reg:CC_V CC_REGNUM) - (compare:CC_V - (neg:TI (plus:TI - (ltu:TI (reg:CC CC_REGNUM) (const_int 0)) - (sign_extend:TI (match_operand:DI 1 "register_operand" "r")))) - (sign_extend:TI - (neg:DI (plus:DI (ltu:DI (reg:CC CC_REGNUM) (const_int 0)) - (match_dup 1)))))) - (set (match_operand:DI 0 "register_operand" "=r") - (neg:DI (plus:DI (ltu:DI (reg:CC CC_REGNUM) (const_int 0)) - (match_dup 1))))] - "" - "ngcs\\t%0, %1" - [(set_attr "type" "alus_sreg")] -) - (define_insn "*sub<mode>3_compare0" [(set (reg:CC_NZ CC_REGNUM) (compare:CC_NZ (minus:GPI (match_operand:GPI 1 "register_operand" "rk") @@ -3370,134 +3356,105 @@ [(set_attr "type" "adc_reg")] ) -(define_expand "usub<GPI:mode>3_carryinC" +(define_expand "sub<mode>3_carryin_cmp" [(parallel - [(set (reg:CC CC_REGNUM) - (compare:CC - (zero_extend:<DWI> - (match_operand:GPI 1 "aarch64_reg_or_zero")) - (plus:<DWI> - (zero_extend:<DWI> - (match_operand:GPI 2 "register_operand")) - (ltu:<DWI> (reg:CC CC_REGNUM) (const_int 0))))) - (set (match_operand:GPI 0 "register_operand") - (minus:GPI - (minus:GPI (match_dup 1) (match_dup 2)) - (ltu:GPI (reg:CC CC_REGNUM) (const_int 0))))])] + [(set (match_dup 3) + (unspec:CC + [(match_operand:GPI 1 "aarch64_reg_or_zero") + (match_operand:GPI 2 "aarch64_reg_zero_minus1") + (match_dup 4)] + UNSPEC_SBCS)) + (set (match_operand:GPI 0 "register_operand" "=r") + (unspec:GPI + [(match_dup 1) (match_dup 2) (match_dup 4)] + UNSPEC_SBCS))])] "" + { + operands[3] = gen_rtx_REG (CCmode, CC_REGNUM); + operands[4] = gen_rtx_LTU (<MODE>mode, operands[3], const0_rtx); + } ) -(define_insn "*usub<GPI:mode>3_carryinC_z1" +(define_insn "*sub<mode>3_carryin_cmp" [(set (reg:CC CC_REGNUM) - (compare:CC - (const_int 0) - (plus:<DWI> - (zero_extend:<DWI> - (match_operand:GPI 1 "register_operand" "r")) - (match_operand:<DWI> 2 "aarch64_borrow_operation" "")))) - (set (match_operand:GPI 0 "register_operand" "=r") - (minus:GPI - (neg:GPI (match_dup 1)) - (match_operand:GPI 3 "aarch64_borrow_operation" "")))] + (unspec:CC + [(match_operand:GPI 1 "aarch64_reg_or_zero" "rZ,rZ") + (match_operand:GPI 2 "aarch64_reg_zero_minus1" "rZ,UsM") + (match_operand:GPI 3 "aarch64_borrow_operation" "")] + UNSPEC_SBCS)) + (set (match_operand:GPI 0 "register_operand" "=r,r") + (unspec:GPI + [(match_dup 1) (match_dup 2) (match_dup 3)] + UNSPEC_SBCS))] "" - "sbcs\\t%<w>0, <w>zr, %<w>1" + "@ + sbcs\\t%<w>0, %<w>1, %<w>2 + adcs\\t%<w>0, %<w>1, <w>zr" [(set_attr "type" "adc_reg")] ) -(define_insn "*usub<GPI:mode>3_carryinC_z2" +(define_expand "cmp<mode>3_carryin" [(set (reg:CC CC_REGNUM) - (compare:CC - (zero_extend:<DWI> - (match_operand:GPI 1 "register_operand" "r")) - (match_operand:<DWI> 2 "aarch64_borrow_operation" ""))) - (set (match_operand:GPI 0 "register_operand" "=r") - (minus:GPI - (match_dup 1) - (match_operand:GPI 3 "aarch64_borrow_operation" "")))] + (unspec:CC + [(match_operand:GPI 0 "aarch64_reg_or_zero") + (match_operand:GPI 1 "aarch64_reg_zero_minus1") + (ltu:GPI (reg:CC CC_REGNUM) (const_int 0))] + UNSPEC_SBCS))] "" - "sbcs\\t%<w>0, %<w>1, <w>zr" - [(set_attr "type" "adc_reg")] ) -(define_insn "*usub<GPI:mode>3_carryinC" +(define_insn "*cmp<mode>3_carryin" [(set (reg:CC CC_REGNUM) - (compare:CC - (zero_extend:<DWI> - (match_operand:GPI 1 "register_operand" "r")) - (plus:<DWI> - (zero_extend:<DWI> - (match_operand:GPI 2 "register_operand" "r")) - (match_operand:<DWI> 3 "aarch64_borrow_operation" "")))) - (set (match_operand:GPI 0 "register_operand" "=r") - (minus:GPI - (minus:GPI (match_dup 1) (match_dup 2)) - (match_operand:GPI 4 "aarch64_borrow_operation" "")))] + (unspec:CC + [(match_operand:GPI 0 "aarch64_reg_or_zero" "rZ,rZ") + (match_operand:GPI 1 "aarch64_reg_zero_minus1" "rZ,UsM") + (match_operand:GPI 2 "aarch64_borrow_operation" "")] + UNSPEC_SBCS))] "" - "sbcs\\t%<w>0, %<w>1, %<w>2" + "@ + sbcs\\t<w>zr, %<w>0, %<w>1 + adcs\\t<w>zr, %<w>0, <w>zr" [(set_attr "type" "adc_reg")] ) -(define_expand "sub<GPI:mode>3_carryinV" - [(parallel - [(set (reg:CC_V CC_REGNUM) - (compare:CC_V - (minus:<DWI> - (sign_extend:<DWI> - (match_operand:GPI 1 "aarch64_reg_or_zero")) - (plus:<DWI> - (sign_extend:<DWI> - (match_operand:GPI 2 "register_operand")) - (ltu:<DWI> (reg:CC CC_REGNUM) (const_int 0)))) - (sign_extend:<DWI> - (minus:GPI (match_dup 1) - (plus:GPI (ltu:GPI (reg:CC CC_REGNUM) (const_int 0)) - (match_dup 2)))))) - (set (match_operand:GPI 0 "register_operand") - (minus:GPI - (minus:GPI (match_dup 1) (match_dup 2)) - (ltu:GPI (reg:CC CC_REGNUM) (const_int 0))))])] - "" +;; If combine can show that the borrow is 0, fold SBCS to SUBS. +(define_insn_and_split "*sub<mode>3_carryin_cmp_0" + [(set (reg:CC CC_REGNUM) + (unspec:CC + [(match_operand:GPI 1 "aarch64_reg_or_zero" "rk,rkZ") + (match_operand:GPI 2 "aarch64_plus_immediate" "rIJ,r") + (const_int 0)] + UNSPEC_SBCS)) + (set (match_operand:GPI 0 "register_operand") + (unspec:GPI + [(match_dup 1) (match_dup 2) (const_int 0)] + UNSPEC_SBCS))] + "" + "#" + "" + [(scratch)] + { + emit_insn (gen_sub<mode>3_compare1 (operands[0], operands[1], + operands[2])); + DONE; + } ) -(define_insn "*sub<mode>3_carryinV_z2" - [(set (reg:CC_V CC_REGNUM) - (compare:CC_V - (minus:<DWI> - (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "r")) - (match_operand:<DWI> 2 "aarch64_borrow_operation" "")) - (sign_extend:<DWI> - (minus:GPI (match_dup 1) - (match_operand:GPI 3 "aarch64_borrow_operation" ""))))) - (set (match_operand:GPI 0 "register_operand" "=r") - (minus:GPI - (match_dup 1) (match_dup 3)))] +(define_insn_and_split "*cmp<mode>3_carryin_0" + [(set (reg:CC CC_REGNUM) + (unspec:CC + [(match_operand:GPI 0 "aarch64_reg_or_zero" "rk,rZ") + (match_operand:GPI 1 "aarch64_plus_operand" "rIJ,r") + (const_int 0)] + UNSPEC_SBCS))] "" - "sbcs\\t%<w>0, %<w>1, <w>zr" - [(set_attr "type" "adc_reg")] -) - -(define_insn "*sub<mode>3_carryinV" - [(set (reg:CC_V CC_REGNUM) - (compare:CC_V - (minus:<DWI> - (sign_extend:<DWI> - (match_operand:GPI 1 "register_operand" "r")) - (plus:<DWI> - (sign_extend:<DWI> - (match_operand:GPI 2 "register_operand" "r")) - (match_operand:<DWI> 3 "aarch64_borrow_operation" ""))) - (sign_extend:<DWI> - (minus:GPI - (match_dup 1) - (plus:GPI (match_operand:GPI 4 "aarch64_borrow_operation" "") - (match_dup 2)))))) - (set (match_operand:GPI 0 "register_operand" "=r") - (minus:GPI - (minus:GPI (match_dup 1) (match_dup 2)) - (match_dup 4)))] + "#" "" - "sbcs\\t%<w>0, %<w>1, %<w>2" - [(set_attr "type" "adc_reg")] + [(scratch)] + { + emit_insn (gen_cmp<mode> (operands[0], operands[1])); + DONE; + } ) (define_insn "*sub_uxt<mode>_shift2" diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md index 215fcec5955..5f44ef7d672 100644 --- a/gcc/config/aarch64/predicates.md +++ b/gcc/config/aarch64/predicates.md @@ -68,6 +68,13 @@ (ior (match_operand 0 "register_operand") (match_test "op == CONST0_RTX (GET_MODE (op))")))) +(define_predicate "aarch64_reg_zero_minus1" + (and (match_code "reg,subreg,const_int") + (ior (match_operand 0 "register_operand") + (ior (match_test "op == CONST0_RTX (GET_MODE (op))") + (match_test "op == CONSTM1_RTX (GET_MODE (op))"))))) + + (define_predicate "aarch64_reg_or_fp_zero" (ior (match_operand 0 "register_operand") (and (match_code "const_double") -- 2.20.1