On Fri, Oct 21, 2011 at 4:41 PM, Richard Henderson <r...@redhat.com> wrote:
> On 10/21/2011 10:15 AM, Paulo J. Matos wrote:
>> So I have implemented the nadd and addc as:
>>
>> (define_insn "negqi2"
>>   [(set (match_operand:QI 0 "register_operand" "=c")
>>         (neg:QI (match_operand:QI 1 "register_operand" "0")))
>>    (set (reg:CC_C RCC) (eq (match_dup 1) (const_int 0)))
>>    (clobber (reg:CC RCC))]
>>   ""
>> {
>>     operands[2] = const0_rtx;
>>     return  "nadd\\t%0,%2";
>> })
>
> There are lots of parts of the compiler that don't optimize well when an
> insn has more than one output.  For the normal insn, just clobber the flags;
> don't include a second SET.

In my similar case, I'm implementing a multi-word rotate by using an
arithmetic shift that overflows into carry, followed by a second rotate
that shifts in from carry for the upper word:

(define_insn "rla<mode>1"
  [(set (match_operand:INTRegModes 0 "nonimmediate_operand" "+rm")
        (ashift:<MODE> (match_dup 0) (const_int 1)))
   (set (reg:CC_C REGNO_SR) (unspec:CC_C [(match_dup 0)] UNSPEC_ROTC))]
  ""
  { return msp430_output_template (<MODE>mode, 0, "rla", NULL); }
  )

(define_insn "rlc<mode>1"
  [(set (match_operand:INTRegModes 0 "nonimmediate_operand" "+rm")
        (unspec:<MODE> [(match_dup 0)] UNSPEC_RLC))
   (use (reg:CC_C REGNO_SR))
   (set (reg:CC_C REGNO_SR) (unspec:CC_C [(match_dup 0)] UNSPEC_ROTC))]
  ""
  { return msp430_output_template (<MODE>mode, 0, "rlc", NULL); }
  )

I found that if I used (clobber (reg:CC_C REGNO_SR)) instead of set that the
dependency was not preserved, and the rlc ended up after the rla in the
final instruction stream.  This is consistent with your previous comment in
this thread:

> The thing that's almost certainly missing is that the NAND pattern
> must SET your flags register, not simply clobber it.  Otherwise the
> dependency between the ADDC and the NAND will never be created properly.

Is there a better way to solve this that doesn't introduce multiple outputs in
one insn?

Peter

>
>> (define_insn "addc_internal"
>>   [(set (match_operand:QI 0 "nonimmediate_operand" "=c")
>>         (plus:QI
>>           (plus:QI
>>             (ltu:QI (reg:CC RCC) (const_int 0))
>>             (match_operand:QI 1 "nonimmediate_operand" "%0"))
>>           (match_operand:QI 2 "general_operand" "cwmi")))
>>    (use (reg:CC_C RCC))
>>    (clobber (reg:CC RCC))]
>>   ""
>>   "addc\\t%0,%f2")
>
> You don't need the USE, because you mention RCC inside the LTU.
>
>> (define_insn "*addc_internal_flags"
>
> Likewise.
>
>> A couple of things to note:
>> * negqi (which generates the nadd x, y equivalent to -x + y) has a
>> set RCC in C mode followed by a clobber. The set in C mode doesn't
>> show up in the _flags variant which is used only for the compare-elim
>> since it doesn't really matter and it already contains a set RCC
>> anyway.
>
> Surely the NADD insn is simply a normal subtract (with reversed operands).
> You shouldn't *need* to implement NEG at all, as the middle-end will let
> NEG expand via MINUS.
>
> Just so you know...
>
>> * is this enough for GCC to understand that anything that clobbers
>> RCC or specifically touches the RCC in C mode shouldn't go in between
>> these two instructions?
>
> Yes.
>
>> Also, do I need to specify in the RCC
>> clobber, exactly which flags are clobbered, or should I use a set
>> instead?
>
> No, the compiler will assume the entire register is changed, no matter
> what CCmode you place there.
>
>> * in the case of using sets, it was easy in the case of the negqi of
>> findind the source of the set RCC, however, it's not so easy for the
>> general case. Is unspec the answer? Is unspec the way of saying:
>> "hey, I am setting RCC in Cmode here, you shouldn't bother about the
>> value that I put there. Just know that RCC is going to be set."
>
> You can often just use (compare x y) as well, assuming that the flags
> are set "appropriately".  GCC doesn't assume anything about the
> contents of the intermediate CCmode object, but does assume that
>
>  (lt (compare x y) (const_int 0))
>
> produces the same value as
>
>  (lt x y)
>
> But, yes, if there's no obvious comparison, then unspec is ok.
>
>
> r~
>

Reply via email to