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