From deb254e029c9430a0c3d0cb044e4ca7b3f15b619 Mon Sep 17 00:00:00 2001 From: Richard Earnshaw Date: Fri, 18 Oct 2019 19:04:15 +0000 Subject: [PATCH] [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 --- gcc/ChangeLog | 15 ++++ gcc/config/arm/arm-modes.def | 4 + gcc/config/arm/arm.c | 16 ++++ gcc/config/arm/arm.md | 171 ++++++++++++++++++++++++++++++++++++++----- gcc/config/arm/predicates.md | 2 +- 5 files changed, 188 insertions(+), 20 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3b8f9f3..902cf51 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,20 @@ 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. * (uaddv4): Delete expansion pattern. (uaddvsi4): New pattern. diff --git a/gcc/config/arm/arm-modes.def b/gcc/config/arm/arm-modes.def index f0eb841..a6b520d 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 6c1e913..fb1a681 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -15388,6 +15388,14 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx 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 && ((GET_CODE (y) == PLUS @@ -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 4ea6f4b..9f0e435 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 d9470df..8a8f10c 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; -- 2.7.4