James E Wilson wrote:
> You were never very clear about what was wrong with gen_highpart and
> gen_lowpart with respect to subregs.  rtl examples are always helpful,
> e.g. showing RTL input and RTL output and pointing out what is wrong.
> gen_lowpart already has support for subreg input and presumably should
> work.
>
> gen_lowpart is already pretty involved.  If you need something other
> than a trivial fix, it might be better to try to solve the problem in
> your md file.
Ok, Indeed I had not been very explicit. So here is the story

1.) Background
avr has *only* qi mode arithmetic operations and needs to split/expand any 
logic or arithmetic operation to individual qi mode operation. Problem of the 
present port is that it pretends presence of HI mode and SI mode operations 
by providing insn like andsi3. The splitting to QI mode operations presently 
is never visible in the RTL and done extremely late at assembly output. Gcc 
misses therefore a lot of optimizations. I am presently trying to remove the 
define_insn for the HImode and SImode operations by implementing the lowering 
to QImode at expand or at least after reload (for those operations that leave 
the condition code in a useable state like addsi3 ).

2.) Where the problem with nested subregs shows up:

One example of one pattern that I have written for implementing, e.g. andhi3 
reads:

(define_insn_and_split "andhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,d")
          (and:HI (match_operand:HI 1 "register_operand" "%0,0")
                  (match_operand:HI 2 "nonmemory_operand" "r,i"))) ]
  ""
  "*{
  /* Keep insn until asm output for handling the case of label refs. */
  if (which_alternative==1)
    {
       return (AS2 (andi,%A0,lo8(%2)) CR_TAB
               AS2 (andi,%B0,hi8(%2)));
     }
  return "bug"; 
}"
  "    reload_completed 
   && ((GET_CODE(operands[2]) == CONST_INT) || REG_P(operands[2]))"
  [(set (subreg:QI (match_dup 0) 0)
        (and:QI (subreg:QI (match_dup 1) 0)
                (subreg:QI (match_dup 2) 0)))
   (set (subreg:QI (match_dup 0) 1)
        (and:QI (subreg:QI (match_dup 1) 1)
                (subreg:QI (match_dup 2) 1)))]
  "if (GET_CODE(operands[2]) == CONST_INT)
     {     
       /* If operands[2] is a register, use the template above. */ 
       /* In case of const ints emmit rtl ourselves for optimizing */
       /*  away andi reg,0xff and replace andi reg,0 by ldi reg,0. */
    ...

I first thought that the second alternative for operands[2] would always 
require that operands[2] itself is a register. It seems, however that there 
still remain some, admittedly rare, occasions, where operands[2] itself is a 
(subreg:HI (reg:SI ) 0). In these cases (subreg:QI ( match_dup 2) 0) 
generates one of the nested subreg expressions.

So I thought about using helper functions and change the templates to 
something similar to
  [(set (subreg:QI (match_dup 0) 0)
        (and:QI (subreg:QI (match_dup 1) 0)
                     (match_dup 3)))
   (set (subreg:QI (match_dup 0) 1)
        (and:QI (subreg:QI (match_dup 1) 1)
                     (match_dup 4)))]
with

operands[3] = gen_lowpart (QImode,operands[2]);
operands[4] = gen_highpart (QImode,operands[2]);

. It seems, however, that this second option does not solve the problem. So 
what I am looking for is a function that takes operands[2] for patterns like 
the one above and returns the appropriate subreg RTL that treats both, the 
case that operands[2] is a regular HImode register and the case that 
operands[2] happens to be a subreg:HI of an even wider mode.

I have tried to find out whether such a function already exists in the 
existing code. Unfortunately, it's a bit hard to guess solely from the 
comments for the functions, e.g. in emit-rtl.c, what the different variants 
of gen_highpart and gen_lowpart, gen_subreg, simplify_subreg, etc. are meant 
to be used for.

Yours,

Björn

Reply via email to