Register constraints + and =

Paulo J. Matos paulo@matos-sorge.com
Fri May 4 15:28:00 GMT 2012


On 04/05/12 14:44, Ian Lance Taylor wrote:
> I agree that there is something wrong here.  I agree that as written
> the constraints for operands 0, 1, and 2 should have a '+'.
>
> That said, a '+' constraint is most useful for a pattern that expands
> into multiple instructions.  I think this would be better written along
> the lines of
>
>    (set (match_operand:QI 2 "register_operand" "=d,c") (const_int 0))
>    (set (mem:BLK (match_operand:QI 3 "register_operand" "0")
>                  (match_operand:QI 4 "register_operand" "1")))
>    (set (match_operand:QI 0 "register_operand" "=d,c")
>         (plus:QI (match_dup 3)
>                  (match_operand:QI 5 "register_operand" "2"))))
>    (set (match_operand:QI 1 "register_operand" "=x,c")
>         (plus:QI (match_dup 4) (match_dup 5)))
>    (clobber (match_scratch:QI 3 "=w,w"))
>
> Also it looks like it might be possible to add a third alternative such
> that that alternative does not require the match_scratch.
>
> Ian
>

Thanks for your suggestion, I use it in my discussion below.

Unfortunately this is in preparation for my block copy instruction bc2.
bc2 instruction takes source address in register RXL, destination in 
RAH, and count in RAL. After bc2, RAL is set to 0, RXL is RXL + RAL 
(source address plus count) and RAH is RAH + RAL (destination address 
plus count). This is specified as:
(define_insn "bc2"
   [(set (reg:QI RAL) (const_int 0))
    (set (mem:BLK (reg:QI RAH)) (mem:BLK (reg:QI RAL)))
    (set (reg:QI RXL) (plus:QI (reg:QI RXL) (reg:QI RAL)))
    (set (reg:QI RAH) (plus:QI (reg:QI RAH) (reg:QI RAL)))]
   "!TARGET_NO_BLOCK_COPY"
   "bc2")

Unfortunately, and due to problems with GCC47 RA (for reasons mentioned 
in thread "GCC47 movmem breaks RA, GCC46 RA is fine") I am having 
trouble getting this to work as well as it did with GCC46. In GCC46 I 
simply generated, during expand, the correct move insns and then 
expanded the bc2 insn (with the hardcoded registers).

In GCC47 that breaks apart the RA, so I am attempting to get RA to 
understand that indeed, there's only one register each of the values can 
end up in. So now I have something:
(define_expand "movmemqi"
   [(set (match_operand:BLK 0 "memory_operand")    ; destination
         (match_operand:BLK 1 "memory_operand"))   ; source
    (use (match_operand:QI 2 "general_operand"))   ; count
    (match_operand 3 "" "")]
   "!TARGET_NO_BLOCK_COPY && !reload_completed"
{ xap_expand_movmemqi(operands[0], operands[1], operands[2]); DONE; })

(define_insn_and_split "movmem_long"
   [(set (match_operand:QI 2 "register_operand" "=d") (const_int 0))
    (set (mem:BLK (match_operand:QI 3 "register_operand" "0"))
         (mem:BLK (match_operand:QI 4 "register_operand" "1")))
    (set (match_operand:QI 0 "register_operand" "=d")
         (plus:QI (match_dup 3)
                  (match_operand:QI 5 "register_operand" "2")))
    (set (match_operand:QI 1 "register_operand" "=x")
         (plus:QI (match_dup 4) (match_dup 5)))
    (clobber (match_scratch:QI 6 "=w"))]
   "!TARGET_NO_BLOCK_COPY"
   "#"
   "&& reload_completed"
   [(const_int 0)]
{
   if(REGNO(operands[2]) == RAH)
   {
     emit_move_insn(operands[6], operands[0]);
     emit_move_insn(operands[0], operands[2]);
     emit_move_insn(operands[2], operands[6]);
   }
   emit_insn(gen_bc2());
   DONE;
})

xap_expand_movmemqi issues a couple of move_insn if they are required 
and then does a gen_movmem_long.

I am playing a trick with GCC here... The constraint 'd' applies to 
register class DATA_REGS, which constains 2 registers: RAL and RAH. When 
GCC allocates then in bc2, one will be assigned to operand0 and other to 
operand2. If operand2 ends up with RAH, then I use the scratch to swap 
operand2 with operand0. The annoying part is that something RA ends up 
allocating a scratch which I won't use because he was smart enough to 
allocate everything in order (operand2 with RAL and operand0 with RAH). 
As a side note, constraint 'x', refers to class ADDR_REGS which only has 
register RXL.

This solution, however, still causes RA spills which weren't caused by 
GCC46, but it is better than the GCC46 solution to hardcode the 
registers straight off expand phase.

Another thing I tried but whose results are terrible (libgcc doesn't 
even compile due to register spills errors) is to have one class just 
for RAL, one just for RAH and use those constraints, thereby avoiding 
the scratch altogether. Turns out GCC doesn't seem to like that.

If you have any further suggestions or ideas that I can try out, please 
let me know.

-- 
PMatos



More information about the Gcc mailing list