In order to improve bit manipulations for avr, patterns like the following can 
be used:

+;; [0].log[4] |= [2].log[4]+[3]
+(define_insn "*iorqi2_shiftrt_bit"
+  [(set (match_operand:QI 0 "register_operand" "=d,r")
+        (ior:QI (and:QI (match_operator:QI 1 "shiftrt_operator"
+                                           [(match_operand:QI 2 "register_operand" 
"r,r")
+                                            (match_operand:QI 3 "const_int_operand" 
"n,n")])
+                        (match_operand:QI 4 "single_one_operand" "n,n"))
+                (match_operand:QI 5 "register_operand" "0,0")))]
+  ""
+  {
+      HOST_WIDE_INT to_bit = exact_log2 (GET_MODE_MASK (QImode) & 
INTVAL(operands[4]));
+      HOST_WIDE_INT from_bit = to_bit + INTVAL(operands[3]);
+
+      operands[3] = GEN_INT (from_bit);
+      operands[4] = GEN_INT (to_bit);
+
+      if (0 == which_alternative)
+          return "sbrc %2,%3\;ori %0,(1<<%4)";
+
+      return "bst %2,%3\;sbrs %0,%4\;bld %0,%4";
+  }
+  [(set_attr "length" "2,3")
+   (set_attr "adjust_len" "no,no")
+   (set_attr "cc" "clobber,none")])
+
+;; needs the above pattern as combiner bridge
+;; [0].log[4] = [2].log[4]+[3]
+(define_insn "*movebit_shiftrt"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+        (ior:QI (and:QI (match_operator:QI 1 "shiftrt_operator"
+                                           [(match_operand:QI 2 "register_operand" 
"r")
+                                            (match_operand:QI 3 "const_int_operand" 
"n")])
+                        (match_operand:QI 4 "single_one_operand" "n"))
+                (and:QI (match_operand:QI 5 "register_operand" "%0")
+                        (match_operand:QI 6 "single_zero_operand" "n"))))] ; = 
~[4]
+  "GET_MODE_MASK (QImode) == (GET_MODE_MASK (QImode) & (INTVAL(operands[4]) ^ 
INTVAL(operands[6])))"
+  {
+      HOST_WIDE_INT to_bit = exact_log2 (GET_MODE_MASK (QImode) & 
INTVAL(operands[4]));
+      HOST_WIDE_INT from_bit = to_bit + INTVAL(operands[3]);
+
+      operands[3] = GEN_INT (from_bit);
+      operands[4] = GEN_INT (to_bit);
+      return "bst %2,%3\;bld %0,%4";
+  }
+  [(set_attr "length" "2")
+   (set_attr "adjust_len" "no")
+   (set_attr "cc" "none")])

The situation for targets like avr is that jumps are quite cheap (no pileline, no cache), 
and shifts are quite expensive (AVR can QI >> 1, QI << 1 and QI rotate 4).

Passes like ifconversion and others transform if-else to arithmetik. 
Canonicalization is nice, because there are many ways to express bit 
manipulations in C (shifts, masking, if-else, conditionals, bitfields, ...) 
However, they are expensive for small targets and therefore backend can help 
out of that with patterns like cited above.

The drawback is that these patterns are pretty much complex, so is there a 
better place to fix the mess (from a tiny target's perspective) that middle end 
produces?
If gcc decides to represent the operations in a slightly different way, the patterns will no more match. That is no problem in itself, but it's hard to test if the patterns are still needed and covered by some source, or if they are dead and just pollute backend. Introducing extzv and insv could bring some effort (I didn't try what impact they have) but basically the problems would remain the same: insn combine stuffs expressions together.
An other drawback of this technique is that the second pattern will never fit without the 
first, because the second is too complex for insn combine. If the first pattern matches 
but won't get combined into the second (because of source), the pattern that is intended 
to serve as a "bridge" for insn combine cannot be undone or rolled back. Note 
that the first pattern is more expensive even though the second is more complex. rtx 
costs could help out of that, but I think no one wants to write/support the above 
patterns as C expressions in rtx_costs...

It is ok to state rtx costs as insn attribute? That would imply to run recog 
from within rtx_costs to scan if for some rtx an insn knows about the costs. 
This would be nice because then there was /one/ place to describe meta 
information about a pattern. This would even help before reload, i.e. if an 
insn has more than one alternative but it's not yet known what alternative will 
actually be chosen. Or would that slow down compilation too much, as recog 
needs time and the pattern to match against must be (re)constructed every time 
(SET must be added)?

Even better would be if the backend allowed to write

+ (define_rtx_cost ; cost for *movebit_shiftrt
+  [(ior:QI (and:QI (match_operator:QI 0 "shiftrt_operator"
+                                     [(match_operand:QI 1 "register_operand" 
"")
+                                      (match_operand:QI 2 "const_int_operand" 
"")])
+                   (match_operand:QI 3 "single_one_operand" ""))
+           (and:QI (match_operand:QI 4 "register_operand" "")
+                   (match_operand:QI 5 "single_zero_operand" ""))))] ; = ~[3]
+  "GET_MODE_MASK (QImode) == (GET_MODE_MASK (QImode) & (INTVAL(operands[3]) ^ 
INTVAL(operands[5])))"
+   (set_attr "rtx_cost" "2")])

or similar rtl.

Georg-Johann

Reply via email to