From: Richard Earnshaw Date: Fri, 18 Oct 2019 19:04:15 +0000 (+0000) Subject: [arm] Early expansion of uaddvdi4. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=deb254e029c9430a0c3d0cb044e4ca7b3f15b619;p=gcc.git [arm] Early expansion of uaddvdi4. This code borrows strongly on the uaddvti4 expansion for aarch64 since the principles are similar. Firstly, if the one of the low words of the expansion is 0, we can simply copy the other low word to the destination and use uaddvsi4 for the upper word. If that doesn't work we have to handle three possible cases for the upper work (the lower word is simply an add-with-carry operation as for adddi3): zero in the upper word, some other constant and a register (each has a different canonicalization). We use CC_ADCmode (a new CC mode variant) to describe the cases as the introduction of the carry means we can no-longer use the normal overflow trick of comparing the sum against one of the operands. * config/arm/arm-modes.def (CC_ADC): New CC mode. * config/arm/arm.c (arm_select_cc_mode): Detect selection of CC_ADCmode. (maybe_get_arm_condition_code): Handle CC_ADCmode. * config/arm/arm.md (uaddvdi4): Early expansion of unsigned addition with overflow. (addsi3_cin_cout_reg, addsi3_cin_cout_imm, addsi3_cin_cout_0): New expand patterns. (addsi3_cin_cout_reg_insn, addsi3_cin_cout_0_insn): New insn patterns (addsi3_cin_cout_imm_insn): Likewise. (adddi3_compareC): Delete insn. * config/arm/predicates.md (arm_carry_operation): Handle CC_ADCmode. From-SVN: r277183 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3b8f9f3f33d..902cf51a37c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2019-10-18 Richard Earnshaw + + * config/arm/arm-modes.def (CC_ADC): New CC mode. + * config/arm/arm.c (arm_select_cc_mode): Detect selection of + CC_ADCmode. + (maybe_get_arm_condition_code): Handle CC_ADCmode. + * config/arm/arm.md (uaddvdi4): Early expansion of unsigned addition + with overflow. + (addsi3_cin_cout_reg, addsi3_cin_cout_imm, addsi3_cin_cout_0): New + expand patterns. + (addsi3_cin_cout_reg_insn, addsi3_cin_cout_0_insn): New insn patterns + (addsi3_cin_cout_imm_insn): Likewise. + (adddi3_compareC): Delete insn. + * config/arm/predicates.md (arm_carry_operation): Handle CC_ADCmode. + 2019-10-18 Richard Earnshaw * config/arm/arm.md (adddi3): Call gen_addsi3_compare_op1. diff --git a/gcc/config/arm/arm-modes.def b/gcc/config/arm/arm-modes.def index f0eb8415b93..a6b520df32d 100644 --- a/gcc/config/arm/arm-modes.def +++ b/gcc/config/arm/arm-modes.def @@ -42,6 +42,9 @@ ADJUST_FLOAT_FORMAT (HF, ((arm_fp16_format == ARM_FP16_FORMAT_ALTERNATIVE) CC_Bmode should be used if only the C flag is correct after a subtract (eg after an unsigned borrow with carry-in propagation). (used for DImode signed comparisons). + CC_ADCmode is used when the carry is formed from the output of ADC for an + addtion. In this case we cannot use the trick of comparing the sum + against one of the other operands. CCmode should be used otherwise. */ CC_MODE (CC_NOOV); @@ -65,6 +68,7 @@ CC_MODE (CC_C); CC_MODE (CC_B); CC_MODE (CC_N); CC_MODE (CC_V); +CC_MODE (CC_ADC); /* Vector modes. */ VECTOR_MODES (INT, 4); /* V4QI V2HI */ diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 6c1e9132ca8..fb1a6810651 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -15387,6 +15387,14 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y) && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y))) return CC_Cmode; + if (GET_MODE (x) == DImode + && GET_CODE (x) == PLUS + && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND + && CONST_INT_P (y) + && UINTVAL (y) == 0x800000000 + && (op == GEU || op == LTU)) + return CC_ADCmode; + if (GET_MODE (x) == DImode && (op == GE || op == LT) && GET_CODE (x) == SIGN_EXTEND @@ -23952,6 +23960,14 @@ maybe_get_arm_condition_code (rtx comparison) default: return ARM_NV; } + case E_CC_ADCmode: + switch (comp_code) + { + case GEU: return ARM_CS; + case LTU: return ARM_CC; + default: return ARM_NV; + } + case E_CCmode: case E_CC_RSBmode: switch (comp_code) diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 4ea6f4b226c..9f0e43571fd 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -517,16 +517,165 @@ (define_expand "uaddvdi4" [(match_operand:DI 0 "s_register_operand") (match_operand:DI 1 "s_register_operand") - (match_operand:DI 2 "s_register_operand") + (match_operand:DI 2 "reg_or_int_operand") (match_operand 3 "")] "TARGET_32BIT" { - emit_insn (gen_adddi3_compareC (operands[0], operands[1], operands[2])); - arm_gen_unlikely_cbranch (LTU, CC_Cmode, operands[3]); + rtx lo_result, hi_result; + rtx lo_op1, hi_op1, lo_op2, hi_op2; + arm_decompose_di_binop (operands[1], operands[2], &lo_op1, &hi_op1, + &lo_op2, &hi_op2); + lo_result = gen_lowpart (SImode, operands[0]); + hi_result = gen_highpart (SImode, operands[0]); + + if (lo_op2 == const0_rtx) + { + emit_move_insn (lo_result, lo_op1); + if (!arm_add_operand (hi_op2, SImode)) + hi_op2 = force_reg (SImode, hi_op2); + + gen_uaddvsi4 (hi_result, hi_op1, hi_op2, operands[3]); + } + else + { + if (!arm_add_operand (lo_op2, SImode)) + lo_op2 = force_reg (SImode, lo_op2); + if (!arm_not_operand (hi_op2, SImode)) + hi_op2 = force_reg (SImode, hi_op2); + + emit_insn (gen_addsi3_compare_op1 (lo_result, lo_op1, lo_op2)); + + if (hi_op2 == const0_rtx) + emit_insn (gen_addsi3_cin_cout_0 (hi_result, hi_op1)); + else if (CONST_INT_P (hi_op2)) + emit_insn (gen_addsi3_cin_cout_imm (hi_result, hi_op1, hi_op2)); + else + emit_insn (gen_addsi3_cin_cout_reg (hi_result, hi_op1, hi_op2)); + + arm_gen_unlikely_cbranch (GEU, CC_ADCmode, operands[3]); + } DONE; }) +(define_expand "addsi3_cin_cout_reg" + [(parallel + [(set (match_dup 3) + (compare:CC_ADC + (plus:DI + (plus:DI (match_dup 4) + (zero_extend:DI (match_operand:SI 1 "s_register_operand"))) + (zero_extend:DI (match_operand:SI 2 "s_register_operand"))) + (const_int 4294967296))) + (set (match_operand:SI 0 "s_register_operand") + (plus:SI (plus:SI (match_dup 5) (match_dup 1)) + (match_dup 2)))])] + "TARGET_32BIT" + { + operands[3] = gen_rtx_REG (CC_ADCmode, CC_REGNUM); + rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM); + operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx); + operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx); + } +) + +(define_insn "*addsi3_cin_cout_reg_insn" + [(set (reg:CC_ADC CC_REGNUM) + (compare:CC_ADC + (plus:DI + (plus:DI + (match_operand:DI 3 "arm_carry_operation" "") + (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%0,r"))) + (zero_extend:DI (match_operand:SI 2 "s_register_operand" "l,r"))) + (const_int 4294967296))) + (set (match_operand:SI 0 "s_register_operand" "=l,r") + (plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "") + (match_dup 1)) + (match_dup 2)))] + "TARGET_32BIT" + "@ + adcs%?\\t%0, %0, %2 + adcs%?\\t%0, %1, %2" + [(set_attr "type" "alus_sreg") + (set_attr "arch" "t2,*") + (set_attr "length" "2,4")] +) + +(define_expand "addsi3_cin_cout_imm" + [(parallel + [(set (match_dup 3) + (compare:CC_ADC + (plus:DI + (plus:DI (match_dup 4) + (zero_extend:DI (match_operand:SI 1 "s_register_operand"))) + (match_dup 6)) + (const_int 4294967296))) + (set (match_operand:SI 0 "s_register_operand") + (plus:SI (plus:SI (match_dup 5) (match_dup 1)) + (match_operand:SI 2 "arm_adcimm_operand")))])] + "TARGET_32BIT" + { + operands[3] = gen_rtx_REG (CC_ADCmode, CC_REGNUM); + rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM); + operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx); + operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx); + operands[6] = GEN_INT (UINTVAL (operands[2]) & 0xffffffff); + } +) + +(define_insn "*addsi3_cin_cout_imm_insn" + [(set (reg:CC_ADC CC_REGNUM) + (compare:CC_ADC + (plus:DI + (plus:DI + (match_operand:DI 3 "arm_carry_operation" "") + (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r,r"))) + (match_operand:DI 5 "const_int_operand" "n,n")) + (const_int 4294967296))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "") + (match_dup 1)) + (match_operand:SI 2 "arm_adcimm_operand" "I,K")))] + "TARGET_32BIT + && (UINTVAL (operands[2]) & 0xffffffff) == UINTVAL (operands[5])" + "@ + adcs%?\\t%0, %1, %2 + sbcs%?\\t%0, %1, #%B2" + [(set_attr "type" "alus_imm")] +) + +(define_expand "addsi3_cin_cout_0" + [(parallel + [(set (match_dup 2) + (compare:CC_ADC + (plus:DI (match_dup 3) + (zero_extend:DI (match_operand:SI 1 "s_register_operand"))) + (const_int 4294967296))) + (set (match_operand:SI 0 "s_register_operand") + (plus:SI (match_dup 4) (match_dup 1)))])] + "TARGET_32BIT" + { + operands[2] = gen_rtx_REG (CC_ADCmode, CC_REGNUM); + rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM); + operands[3] = gen_rtx_LTU (DImode, ccin, const0_rtx); + operands[4] = gen_rtx_LTU (SImode, ccin, const0_rtx); + } +) + +(define_insn "*addsi3_cin_cout_0_insn" + [(set (reg:CC_ADC CC_REGNUM) + (compare:CC_ADC + (plus:DI + (match_operand:DI 2 "arm_carry_operation" "") + (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r"))) + (const_int 4294967296))) + (set (match_operand:SI 0 "s_register_operand" "=r") + (plus:SI (match_operand:SI 3 "arm_carry_operation" "") (match_dup 1)))] + "TARGET_32BIT" + "adcs%?\\t%0, %1, #0" + [(set_attr "type" "alus_imm")] +) + (define_expand "addsi3" [(set (match_operand:SI 0 "s_register_operand") (plus:SI (match_operand:SI 1 "s_register_operand") @@ -636,22 +785,6 @@ (set_attr "type" "alus_sreg")] ) -(define_insn "adddi3_compareC" - [(set (reg:CC_C CC_REGNUM) - (compare:CC_C - (plus:DI - (match_operand:DI 1 "register_operand" "r") - (match_operand:DI 2 "register_operand" "r")) - (match_dup 1))) - (set (match_operand:DI 0 "register_operand" "=&r") - (plus:DI (match_dup 1) (match_dup 2)))] - "TARGET_32BIT" - "adds\\t%Q0, %Q1, %Q2;adcs\\t%R0, %R1, %R2" - [(set_attr "conds" "set") - (set_attr "length" "8") - (set_attr "type" "multiple")] -) - (define_insn "addsi3_compare0" [(set (reg:CC_NOOV CC_REGNUM) (compare:CC_NOOV diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index d9470df8093..8a8f10ccb50 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -376,7 +376,7 @@ machine_mode ccmode = GET_MODE (op0); if (ccmode == CC_Cmode) return GET_CODE (op) == LTU; - else if (ccmode == CCmode || ccmode == CC_RSBmode) + else if (ccmode == CCmode || ccmode == CC_RSBmode || ccmode == CC_ADCmode) return GET_CODE (op) == GEU; return false;