ivopts-caused "unrecognized insn"

Cynbe ru Taren cynbe@muq.org
Wed Sep 26 23:10:00 GMT 2012



Ian Lance Taylor <iant@google.com> writes:
> On Wed, Sep 26, 2012 at 1:11 PM, Cynbe ru Taren <cynbe@muq.org> wrote:
>>
>> Ian Lance Taylor <iant@google.com> writes:
>>
>>> No, addsi3 is a named pattern and you could and should use define_expand.
>>>
>>> Ian
>>
>> That is an excellent hint -- thank you!
>>
>> Might I ask what the advantage of define_expand is in this case?
> 
> You can generate a different insn sequence if the constant is too large.

Ok, that is the part I'm not understanding.
(Many thanks for your patience with a gcc newbie!)

The sequence of events is:

1) Immediate constant is in range (i.e., fits in signed 16-bit field)
   at RTL generation time so the tried-and-true rule

      (define_insn "addsi3"
        [(set (match_operand:SI 0 "register_operand"      "=r,r")
          (plus:SI (match_operand:SI 1 "register_operand" "%r,r")
                  (match_operand:SI 2 "arith_operand"      "r,I")))]
        ""
        "add%i2\\t%0, %1, %z2"
        [(set_attr "type" "alu")])

   fires in the expectation of generating an "addi" with 16-bit immediate constant.

2) During the "ivopts" pass, the constant is rewritten to no longer fit in 16 bits.
   This is rare -- I currently only know of two cases of this happening in the wild.
   I can post the transformation details if required, but all that really matters
   for current purposes is that in fact it happens.

3) Consequently during the "vregs" pass compiler crashes with "unrecognizable insn"
   because the above RTL template no longer matches once the constant is out of range.


I can prevent the crash and generate code by providing an alternate template via

    (define_insn "*addsi3"
      [(set (match_operand:SI 0 "register_operand"          "=r")
            (plus:SI (match_operand:SI 1 "register_operand" "%r")
                     (match_operand:SI 2 "const_int_operand" "i")))]
      ""
      "movhi\\tat, %H2\;addi\\tat, at, %L2\;add\\t%0, %1, at"
      [(set_attr "type" "alu")])

which -will- match even after "ivopts" has done its mangling.  But it needs a
scratch register for its code sequence, and I'm abusing a register reserved
for another purpose. ("at" -- "assembler temporary". R1.)

I would like to use some facility like "match_scratch" to allocate the needed
scratch register fair and square, but I'm not sure how to get that allocation
done after the "ivopts" pass, when the need for it first becomes apparent.



Are you saying that I can include logic in my define_expand which will
correctly predict that "ivopts" will modify the constant to no longer
fit in 16 bits, and expand an alternate suitable insn sequence based on
that foreknowledge?  (That seems like a tall order! :-)

Or are you saying that there is some way to arrange for define_expand
logic to run after the "ivopts" pass and before the "vregs" pass, so
as to re-select appropriate RTL based on the results of the "ivopts"
pass modifications to the RTL?

(Sorry if I'm being a little slow here!)


So far as I can see at the moment, I have to always allocate a scratch
register at define_expand time even though it will only be used in the
very rare cases where "ivopts" rewrites the constant to be out of range,
which basically means throwing away one register almost every time I
generate an 'addi'.  Nios2 is a relatively register-rich architecture,
so that isn't out of the question, but it is certainly suboptimal and
irritating. (Ignoring the fact that I haven't yet quite worked out how
to do that. :-)

If this is really the case, simply continuing to abuse the "at"
register is starting to look like the least evil...

Thanks again for your patience with an ignorant gcc newbie!

-- Cynbe



More information about the Gcc-help mailing list