This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

ivopts-caused "unrecognized insn"


I have a problem on the Altera Nios2 architecture
(it is a bit like MIPS) with

    (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")])

This is mostly old and stable and straightforward and in production use
for half a decade; the main point of interest is that the 'I' argument
represents a 16-bit signed immediate value on a 32-bit architecture.

When compiling the simple stimulus program

    #define MAX 200
    char a[MAX*256];
    int main()
    {
      int i;
      for (i=0; i<MAX; i++)
        {
          a[i*256] = 0.0;
          a[i] = 0.0;
        }
      return 0;
    }

at -O2 -fpic what happens is that the above define_insn matches fine originally
but during pass "ivopts" induction variable elimination rewrites the
immediate constant to be out of range, resulting in "unrecognizable insn".


After peering at gcc.gnu.org/onlinedocs/gccint/* awhile my first thought
was to add to my nios2.md

        ;; Split an add that we can't do in one insn into two insns, each of which
        ;; does one 16-bit part.  This is used by combine.  Note that the low-order
        ;; add should be last in case the result gets used in an address.

        (define_split
          [(set (match_operand:SI 0 "gpc_reg_operand" "")
                (plus:SI (match_operand:SI 1 "gpc_reg_operand" "")
                          (match_operand:SI 2 "non_add_cint_operand" "")))]
          ""
          [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
           (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
        "
        {
          HOST_WIDE_INT val = INTVAL (operands[2]);
          HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
          HOST_WIDE_INT rest = trunc_int_for_mode (val - low, SImode);

          operands[3] = GEN_INT (rest);
          operands[4] = GEN_INT (low);
        }")

but (as I quickly discovered!) this will not take effect until
pass "combine", whereas I'm crashing 14 passes earlier in "vregs", as soon as
the volatile_ok global is set to 1, forcing all insns to have a valid
match to a defined insn.


My second thought was to add to my nios2.md

    (define_insn ""
     [(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")))
       (clobber     (match_scratch:SI 3                   "=&r"))]
     ""
     "movhi\\t%3, %H2\;addi\\t%3, %3, %L2\;add%i2\\t%0, %1, %3"
     [(set_attr "type" "alu")])

so that when the ivopts transform converts the rtx into something the
"addsi3" would no longer recognize, the above anonymous def would kick
in and match, and at assembly time eventually substitute an instruction
sequence capable of handling 32-bit immediate constants for the original
single instruction with its 16-bit immediate constant limitation.

Which might be roughly the right idea so far as it goes (?) but when
I try adding the above to nios2.md and rebuilding the toolchain I get
another "unrecognizable insn" off in a completely different file (libgcc2.c):

    ../../src/gcc-4.1/gcc/libgcc2.c: In function '__muldi3':
    ../../src/gcc-4.1/gcc/libgcc2.c:542: error: unrecognizable insn:
    (insn 112 48 50 1 ../../src/gcc-4.1/gcc/libgcc2.c:536 (set (reg:SI 2 r2)
            (scratch:SI)) -1 (nil)
        (nil))
    ../../src/gcc-4.1/gcc/libgcc2.c:542: internal compiler error: in extract_insn, at recog.c:2093


Searching on the above I find a similar report back in 2009 to which
Ian Lance Taylor suggested using a define_expand, but according to the
manual define_expand is useful only when named, for generating rtx,
whereas my (initial) problem is matching rtx, rather than generating
it, if I understand correctly.


Gcc is terra incognita to me and I seem to be in a bit over my head.
I'm going to continue mucking around trying stuff and learning
more about gcc internals, but I have a feeling this is one of those
times where a little assistance from an experienced gcc hand could
save a lot of time. :-)

Thanks in advance for any help!

-- Cynbe


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]