Similar to UNSPEC_SBCS, we can unify the signed/unsigned overflow paths by using an unspec.
Accept -1 for the second input by using SBCS. * config/aarch64/aarch64.md (UNSPEC_ADCS): New. (addvti4, uaddvti4): Use adddi_carryin_cmp. (add<GPI>3_carryinC): Remove. (*add<GPI>3_carryinC_zero): Remove. (*add<GPI>3_carryinC): Remove. (add<GPI>3_carryinV): Remove. (*add<GPI>3_carryinV_zero): Remove. (*add<GPI>3_carryinV): Remove. (add<GPI>3_carryin_cmp): New expander. (*add<GPI>3_carryin_cmp): New pattern. (*add<GPI>3_carryin_cmp_0): New pattern. (*cmn<GPI>3_carryin): New pattern. (*cmn<GPI>3_carryin_0): New pattern. --- gcc/config/aarch64/aarch64.md | 206 +++++++++++++++------------------- 1 file changed, 89 insertions(+), 117 deletions(-) diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 564dea390be..99023494fa1 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_ADCS UNSPEC_SBCS ]) @@ -2062,7 +2063,7 @@ aarch64_expand_addsubti (operands[0], operands[1], operands[2], CODE_FOR_adddi3_compareV, CODE_FOR_adddi3_compareC, - CODE_FOR_adddi3_carryinV); + CODE_FOR_adddi3_carryin_cmp); aarch64_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]); DONE; }) @@ -2077,7 +2078,7 @@ aarch64_expand_addsubti (operands[0], operands[1], operands[2], CODE_FOR_adddi3_compareC, CODE_FOR_adddi3_compareC, - CODE_FOR_adddi3_carryinC); + CODE_FOR_adddi3_carryin_cmp); aarch64_gen_unlikely_cbranch (GEU, CC_ADCmode, operands[3]); DONE; }) @@ -2579,133 +2580,104 @@ [(set_attr "type" "adc_reg")] ) -(define_expand "add<mode>3_carryinC" +(define_expand "add<mode>3_carryin_cmp" [(parallel - [(set (match_dup 3) - (compare:CC_ADC - (plus:<DWI> - (plus:<DWI> - (match_dup 4) - (zero_extend:<DWI> - (match_operand:GPI 1 "register_operand"))) - (zero_extend:<DWI> - (match_operand:GPI 2 "register_operand"))) - (match_dup 6))) - (set (match_operand:GPI 0 "register_operand") - (plus:GPI - (plus:GPI (match_dup 5) (match_dup 1)) - (match_dup 2)))])] + [(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_ADCS)) + (set (match_operand:GPI 0 "register_operand") + (unspec:GPI + [(match_dup 1) (match_dup 2) (match_dup 4)] + UNSPEC_ADCS))])] "" -{ - operands[3] = gen_rtx_REG (CC_ADCmode, CC_REGNUM); - rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM); - operands[4] = gen_rtx_LTU (<DWI>mode, ccin, const0_rtx); - operands[5] = gen_rtx_LTU (<MODE>mode, ccin, const0_rtx); - operands[6] = immed_wide_int_const (wi::shwi (1, <DWI>mode) - << GET_MODE_BITSIZE (<MODE>mode), - TImode); -}) + { + operands[3] = gen_rtx_REG (CCmode, CC_REGNUM); + operands[4] = gen_rtx_GEU (<MODE>mode, operands[3], const0_rtx); + } +) -(define_insn "*add<mode>3_carryinC_zero" - [(set (reg:CC_ADC CC_REGNUM) - (compare:CC_ADC - (plus:<DWI> - (match_operand:<DWI> 2 "aarch64_carry_operation" "") - (zero_extend:<DWI> (match_operand:GPI 1 "register_operand" "r"))) - (match_operand 4 "const_scalar_int_operand" ""))) - (set (match_operand:GPI 0 "register_operand" "=r") - (plus:GPI (match_operand:GPI 3 "aarch64_carry_operation" "") - (match_dup 1)))] - "rtx_mode_t (operands[4], <DWI>mode) - == (wi::shwi (1, <DWI>mode) << (unsigned) GET_MODE_BITSIZE (<MODE>mode))" - "adcs\\t%<w>0, %<w>1, <w>zr" +(define_insn "*add<mode>3_carryin_cmp" + [(set (reg:CC CC_REGNUM) + (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_carry_operation" "")] + UNSPEC_ADCS)) + (set (match_operand:GPI 0 "register_operand" "=r,r") + (unspec:GPI + [(match_dup 1) (match_dup 2) (match_dup 3)] + UNSPEC_ADCS))] + "" + "@ + adcs\\t%<w>0, %<w>1, %<w>2 + sbcs\\t%<w>0, %<w>1, <w>zr" [(set_attr "type" "adc_reg")] ) -(define_insn "*add<mode>3_carryinC" - [(set (reg:CC_ADC CC_REGNUM) - (compare:CC_ADC - (plus:<DWI> - (plus:<DWI> - (match_operand:<DWI> 3 "aarch64_carry_operation" "") - (zero_extend:<DWI> (match_operand:GPI 1 "register_operand" "r"))) - (zero_extend:<DWI> (match_operand:GPI 2 "register_operand" "r"))) - (match_operand 5 "const_scalar_int_operand" ""))) - (set (match_operand:GPI 0 "register_operand" "=r") - (plus:GPI - (plus:GPI (match_operand:GPI 4 "aarch64_carry_operation" "") - (match_dup 1)) - (match_dup 2)))] - "rtx_mode_t (operands[5], <DWI>mode) - == (wi::shwi (1, <DWI>mode) << (unsigned) GET_MODE_BITSIZE (<MODE>mode))" - "adcs\\t%<w>0, %<w>1, %<w>2" +(define_insn "*cmn<mode>3_carryin" + [(set (reg:CC CC_REGNUM) + (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_carry_operation" "")] + UNSPEC_ADCS))] + "" + "@ + adcs\\t<w>zr, %<w>0, %<w>1 + sbcs\\t<w>zr, %<w>0, <w>zr" [(set_attr "type" "adc_reg")] ) -(define_expand "add<mode>3_carryinV" - [(parallel - [(set (reg:CC_V CC_REGNUM) - (compare:CC_V - (plus:<DWI> - (plus:<DWI> - (match_dup 3) - (sign_extend:<DWI> - (match_operand:GPI 1 "register_operand"))) - (sign_extend:<DWI> - (match_operand:GPI 2 "register_operand"))) - (sign_extend:<DWI> - (plus:GPI - (plus:GPI (match_dup 4) (match_dup 1)) - (match_dup 2))))) - (set (match_operand:GPI 0 "register_operand") - (plus:GPI - (plus:GPI (match_dup 4) (match_dup 1)) - (match_dup 2)))])] - "" -{ - rtx cc = gen_rtx_REG (CC_Cmode, CC_REGNUM); - operands[3] = gen_rtx_LTU (<DWI>mode, cc, const0_rtx); - operands[4] = gen_rtx_LTU (<MODE>mode, cc, const0_rtx); -}) - -(define_insn "*add<mode>3_carryinV_zero" - [(set (reg:CC_V CC_REGNUM) - (compare:CC_V - (plus:<DWI> - (match_operand:<DWI> 2 "aarch64_carry_operation" "") - (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "r"))) - (sign_extend:<DWI> - (plus:GPI - (match_operand:GPI 3 "aarch64_carry_operation" "") - (match_dup 1))))) +;; If combine can show that the borrow is 0, fold ADCS to ADDS. +(define_insn_and_split "*add<mode>3_carryin_cmp_0" + [(set (reg:CC CC_REGNUM) + (unspec:CC + [(match_operand:GPI 1 "aarch64_reg_or_zero" "%rk") + (match_operand:GPI 2 "aarch64_plus_immediate" "rIJ") + (const_int 0)] + UNSPEC_ADCS)) (set (match_operand:GPI 0 "register_operand" "=r") - (plus:GPI (match_dup 3) (match_dup 1)))] - "" - "adcs\\t%<w>0, %<w>1, <w>zr" - [(set_attr "type" "adc_reg")] + (unspec:GPI + [(match_dup 1) (match_dup 2) (const_int 0)] + UNSPEC_ADCS))] + "" + "#" + "" + [(scratch)] + { + if (CONST_INT_P (operands[1])) + { + /* If operand2 is also constant, this must be before reload. + Expanding this to an explicit plus of two constants would + result in invalid rtl. */ + if (CONST_INT_P (operands[2])) + FAIL; + std::swap (operands[1], operands[2]); + } + emit_insn (gen_add<mode>3_compare0 (operands[0], operands[1], + operands[2])); + DONE; + } ) -(define_insn "*add<mode>3_carryinV" - [(set (reg:CC_V CC_REGNUM) - (compare:CC_V - (plus:<DWI> - (plus:<DWI> - (match_operand:<DWI> 3 "aarch64_carry_operation" "") - (sign_extend:<DWI> (match_operand:GPI 1 "register_operand" "r"))) - (sign_extend:<DWI> (match_operand:GPI 2 "register_operand" "r"))) - (sign_extend:<DWI> - (plus:GPI - (plus:GPI - (match_operand:GPI 4 "aarch64_carry_operation" "") - (match_dup 1)) - (match_dup 2))))) - (set (match_operand:GPI 0 "register_operand" "=r") - (plus:GPI - (plus:GPI (match_dup 4) (match_dup 1)) - (match_dup 2)))] - "" - "adcs\\t%<w>0, %<w>1, %<w>2" - [(set_attr "type" "adc_reg")] +;; ??? There's no one add*compare*cconly pattern that covers both C and V +;; into which this can be split. Leave it whole for now. +(define_insn "*cmn<mode>3_carryin_0" + [(set (reg:CC CC_REGNUM) + (unspec:CC + [(match_operand:GPI 0 "aarch64_reg_or_zero" "%rk,rk,rZ") + (match_operand:GPI 1 "aarch64_plus_operand" "I,J,rZ") + (const_int 0)] + UNSPEC_ADCS))] + "" + "@ + cmn\\t%<w>0, %<w>1 + cmp\\t%<w>0, #%n1 + cmn\\t%<w>0, %<w>1" + [(set_attr "type" "alus_imm,alus_imm,alus_sreg")] ) (define_insn "*add_uxt<mode>_shift2" -- 2.20.1