From patchwork Thu Jul 15 15:15:23 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: ARM patch: New cbranchqi, cbranchhi patterns for Thumb-1 Date: Thu, 15 Jul 2010 05:15:23 -0000 From: Bernd Schmidt X-Patchwork-Id: 58988 Message-Id: <4C3F260B.7060309@codesourcery.com> To: Richard Earnshaw Cc: GCC Patches On 07/15/2010 04:43 PM, Richard Earnshaw wrote: > > On Thu, 2010-07-15 at 15:24 +0200, Bernd Schmidt wrote: >> On Thumb-1, comparisons of integer values smaller than a word can be >> done by shifting the value to the left. This patch adds a new macroized >> pattern, cbranch4_insn, which is used for QImode and HImode, and >> does exactly that. Effects: >> >> - lsl r2, r1, #24 >> - lsr r2, r2, #24 >> - cmp r2, #0 >> + lsl r1, #24 >> bne .L195 > This is going to only set the N and Z flags correctly. V and C will > have different values. You're right. A while ago I posted another patch which introduced noov_comparison_operator; it seems like that could be used here as well. We can handle the other cases by inserting an extra compare with zero. New patch attached, this also makes use of the fact that constant shifts are three-operand even on Thumb-1, so we can use any register as scratch. > Also note, the same trick should be usable on ARM and Thumb2 if we don't > do that already. On the whole my impression is that being able to manipulate comparison insns directly makes things a lot easier for the compiler in TARGET_32BIT mode. I'm not sure we need this trick, I'd expect the combiner can already do this. Bernd * config/arm/arm.md (QHI): New define_mode_iterator. (cbranch4_insn): New pattern. * config/arm/predicates.md (noov_comparison_operator): New predicate. Index: config/arm/arm.md =================================================================== --- config/arm/arm.md.orig +++ config/arm/arm.md @@ -393,6 +393,9 @@ ;; The integer modes up to word size (define_mode_iterator QHSI [QI HI SI]) +;; The integer modes below word size +(define_mode_iterator QHI [QI HI]) + ;;--------------------------------------------------------------------------- ;; Predicates @@ -6686,6 +6689,63 @@ (const_int 8))))] ) +(define_mode_attr mode_lshift [(QI "24") (HI "16")]) + +(define_insn "cbranch4_insn" + [(set (pc) (if_then_else + (match_operator 0 "arm_comparison_operator" + [(match_operand:QHI 1 "s_register_operand" "l") + (const_int 0)]) + (label_ref (match_operand 2 "" "")) + (pc))) + (clobber (match_scratch:QHI 3 "=l"))] + "TARGET_THUMB1" +{ + int len = get_attr_length (insn); + output_asm_insn ("lsl\t%3, %1, #", operands); + + if (!noov_comparison_operator (operands[0], VOIDmode)) + { + output_asm_insn ("cmp\t%3, #0", operands); + len -= 2; + } + + switch (len) + { + case 4: return "b%d0\t%l2"; + case 6: return "b%D0\t.LCB%=\;b\t%l2\t%@long jump\n.LCB%=:"; + default: return "b%D0\t.LCB%=\;bl\t%l2\t%@far jump\n.LCB%=:"; + } +} + [(set (attr "far_jump") + (if_then_else + (ior (and (match_operand 0 "noov_comparison_operator") + (eq_attr "length" "8")) + (eq_attr "length" "10")) + (const_string "yes") + (const_string "no"))) + (set (attr "length") + (if_then_else + (match_operand 0 "noov_comparison_operator") + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -250)) + (le (minus (match_dup 2) (pc)) (const_int 256))) + (const_int 4) + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -2040)) + (le (minus (match_dup 2) (pc)) (const_int 2048))) + (const_int 6) + (const_int 8))) + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -248)) + (le (minus (match_dup 2) (pc)) (const_int 256))) + (const_int 6) + (if_then_else + (and (ge (minus (match_dup 2) (pc)) (const_int -2038)) + (le (minus (match_dup 2) (pc)) (const_int 2048))) + (const_int 8) + (const_int 10)))))]) + (define_insn "cbranchsi4_scratch" [(set (pc) (if_then_else (match_operator 4 "arm_comparison_operator" Index: config/arm/predicates.md =================================================================== --- config/arm/predicates.md.orig +++ config/arm/predicates.md @@ -235,6 +235,9 @@ (define_special_predicate "lt_ge_comparison_operator" (match_code "lt,ge")) +(define_special_predicate "noov_comparison_operator" + (match_code "lt,ge,eq,ne")) + (define_special_predicate "minmax_operator" (and (match_code "smin,smax,umin,umax") (match_test "mode == GET_MODE (op)")))