From f9b9980e6d45565807cb14ef53ab5d02b4338643 Mon Sep 17 00:00:00 2001 From: Richard Earnshaw Date: Tue, 7 Oct 2003 08:49:36 +0000 Subject: [PATCH] arm.md (cmpsi2_addneg): New ARM pattern. * arm.md (cmpsi2_addneg): New ARM pattern. Add peephole2 to generate it. (cbranchne_decr1): New Thumb pattern. * arm.c (arm_addimm_operand): New insn predicate. * arm-protos.h: Add a prototype for it. * arm.h (PREDICATE_CODES): Add it. From-SVN: r72188 --- gcc/ChangeLog | 9 +++ gcc/config/arm/arm-protos.h | 1 + gcc/config/arm/arm.c | 9 +++ gcc/config/arm/arm.h | 1 + gcc/config/arm/arm.md | 156 ++++++++++++++++++++++++++++++++++++ 5 files changed, 176 insertions(+) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3298828987b..f8e3e054510 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2003-10-07 Richard Earnshaw + + * arm.md (cmpsi2_addneg): New ARM pattern. Add peephole2 to generate + it. + (cbranchne_decr1): New Thumb pattern. + * arm.c (arm_addimm_operand): New insn predicate. + * arm-protos.h: Add a prototype for it. + * arm.h (PREDICATE_CODES): Add it. + 2003-10-07 Dorit Naishlos * sched-int.h (sched_info): New field diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index fe424d7c22e..c16deb63a24 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -65,6 +65,7 @@ extern int arm_reload_memory_operand (rtx, enum machine_mode); extern int arm_rhs_operand (rtx, enum machine_mode); extern int arm_rhsm_operand (rtx, enum machine_mode); extern int arm_add_operand (rtx, enum machine_mode); +extern int arm_addimm_operand (rtx, enum machine_mode); extern int arm_not_operand (rtx, enum machine_mode); extern int offsettable_memory_operand (rtx, enum machine_mode); extern int alignable_memory_operand (rtx, enum machine_mode); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index a810791291e..f2441a0ee22 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -3750,6 +3750,15 @@ arm_add_operand (rtx op, enum machine_mode mode) || const_ok_for_arm (-INTVAL (op))))); } +/* Return TRUE for valid ARM constants (or when valid if negated). */ +int +arm_addimm_operand (rtx op, enum machine_mode mode) +{ + return (GET_CODE (op) == CONST_INT + && (const_ok_for_arm (INTVAL (op)) + || const_ok_for_arm (-INTVAL (op)))); +} + int arm_not_operand (rtx op, enum machine_mode mode) { diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index dc21b534e2e..77debec618d 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -2681,6 +2681,7 @@ extern int making_const_table; {"arm_hard_register_operand", {REG}}, \ {"f_register_operand", {SUBREG, REG}}, \ {"arm_add_operand", {SUBREG, REG, CONST_INT}}, \ + {"arm_addimm_operand", {CONST_INT}}, \ {"fpa_add_operand", {SUBREG, REG, CONST_DOUBLE}}, \ {"fpa_rhs_operand", {SUBREG, REG, CONST_DOUBLE}}, \ {"arm_rhs_operand", {SUBREG, REG, CONST_INT}}, \ diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 4a72c69ef3c..177d54b89aa 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -667,6 +667,60 @@ [(set_attr "conds" "set")] ) +;; This is the canonicalization of addsi3_compare0_for_combiner when the +;; addend is a constant. +(define_insn "*cmpsi2_addneg" + [(set (reg:CC CC_REGNUM) + (compare:CC + (match_operand:SI 1 "s_register_operand" "r,r") + (match_operand:SI 2 "arm_addimm_operand" "I,L"))) + (set (match_operand:SI 0 "s_register_operand" "=r,r") + (plus:SI (match_dup 1) + (match_operand:SI 3 "arm_addimm_operand" "L,I")))] + "TARGET_ARM && INTVAL (operands[2]) == -INTVAL (operands[3])" + "@ + sub%?s\\t%0, %1, %2 + add%?s\\t%0, %1, #%n2" + [(set_attr "conds" "set")] +) + +;; Convert the sequence +;; sub rd, rn, #1 +;; cmn rd, #1 (equivalent to cmp rd, #-1) +;; bne dest +;; into +;; subs rd, rn, #1 +;; bcs dest ((unsigned)rn >= 1) +;; similarly for the beq variant using bcc. +;; This is a common looping idiom (while (n--)) +(define_peephole2 + [(set (match_operand:SI 0 "s_register_operand" "") + (plus:SI (match_operand:SI 1 "s_register_operand" "") + (const_int -1))) + (set (match_operand 2 "cc_register" "") + (compare (match_dup 0) (const_int -1))) + (set (pc) + (if_then_else (match_operator 3 "equality_operator" + [(match_dup 2) (const_int 0)]) + (match_operand 4 "" "") + (match_operand 5 "" "")))] + "TARGET_ARM && peep2_reg_dead_p (3, operands[2])" + [(parallel[ + (set (match_dup 2) + (compare:CC + (match_dup 1) (const_int 1))) + (set (match_dup 0) (plus:SI (match_dup 1) (const_int -1)))]) + (set (pc) + (if_then_else (match_op_dup 3 [(match_dup 2) (const_int 0)]) + (match_dup 4) + (match_dup 5)))] + "operands[2] = gen_rtx_REG (CCmode, CC_REGNUM); + operands[3] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE + ? GEU : LTU), + VOIDmode, + operands[2], const0_rtx);" +) + ;; The next four insns work because they compare the result with one of ;; the operands, and we know that the use of the condition code is ;; either GEU or LTU, so we can use the carry flag from the addition @@ -5192,6 +5246,108 @@ (const_int 8))))] ) +(define_insn "*cbranchne_decr1" + [(set (pc) + (if_then_else (match_operator 3 "equality_operator" + [(match_operand:SI 2 "s_register_operand" "l,l,1,l") + (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc))) + (set (match_operand:SI 0 "s_register_operand" "=l,?h,?m,?m") + (plus:SI (match_dup 2) (const_int -1))) + (clobber (match_scratch:SI 1 "=X,l,&l,&l"))] + "TARGET_THUMB" + "* + { + rtx cond[2]; + cond[0] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE + ? GEU : LTU), + VOIDmode, NULL, NULL); + cond[1] = operands[4]; + + if (which_alternative == 0) + output_asm_insn (\"sub\\t%0, %2, #1\", operands); + else if (which_alternative == 1) + { + /* We must provide an alternative for a hi reg because reload + cannot handle output reloads on a jump instruction, but we + can't subtract into that. Fortunately a mov from lo to hi + does not clobber the condition codes. */ + output_asm_insn (\"sub\\t%1, %2, #1\", operands); + output_asm_insn (\"mov\\t%0, %1\", operands); + } + else + { + /* Similarly, but the target is memory. */ + output_asm_insn (\"sub\\t%1, %2, #1\", operands); + output_asm_insn (\"str\\t%1, %0\", operands); + } + + switch (get_attr_length (insn) - (which_alternative ? 2 : 0)) + { + case 4: + output_asm_insn (\"b%d0\\t%l1\", &cond); + return \"\"; + case 6: + output_asm_insn (\"b%D0\\t.LCB%=\", &cond); + return \"b\\t%l4\\t%@long jump\\n.LCB%=:\"; + default: + output_asm_insn (\"b%D0\\t.LCB%=\", &cond); + return \"bl\\t%l4\\t%@far jump\\n.LCB%=:\"; + } + } + " + [(set (attr "far_jump") + (if_then_else + (ior (and (eq (symbol_ref ("which_alternative")) + (const_int 0)) + (eq_attr "length" "8")) + (eq_attr "length" "10")) + (const_string "yes") + (const_string "no"))) + (set_attr_alternative "length" + [ + ;; Alternative 0 + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -250)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2040)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))) + ;; Alternative 1 + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -248)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10))) + ;; Alternative 2 + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -248)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10))) + ;; Alternative 3 + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -248)) + (le (minus (match_dup 4) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 4) (pc)) (const_int -2038)) + (le (minus (match_dup 4) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10)))])] +) ;; Comparison and test insns -- 2.30.2