int a, b, c, d; long long fn1(long long p2) { return p2 == 0 ? -1 : -1 % p2; } void fn2(long long p1, short p2, long p3) { b = fn1((d || 6) & a); c = b | p3; } Compiled for arm-none-eabi with -O1 -mfloat-abi=hard -mfpu=neon -mbig-endian -march=armv7-a ICEs with: anddi.c: In function 'fn2': anddi.c:6:1: error: insn does not satisfy its constraints: } ^ (insn 13 11 14 2 (set (reg:DI 0 r0 [124]) (and:DI (reg:DI 1 r1 [orig:121+-4 ] [121]) (const_int 1 [0x1]))) "anddi.c":2 79 {*anddi3_insn} (nil)) during RTL pass: reload anddi.c:6:1: internal compiler error: in extract_constrain_insn, at recog.c:2205 0xb6d56c _fatal_insn(char const*, rtx_def const*, char const*, int, char const*) $SRC/gcc/rtl-error.c:108 0xb6d59d _fatal_insn_not_found(rtx_def const*, char const*, int, char const*) $SRC/gcc/rtl-error.c:119 0xb40af6 extract_constrain_insn(rtx_insn*) $SRC/gcc/recog.c:2205 0xa3d659 check_rtl $SRC/gcc/lra.c:2156 0xa42258 lra(_IO_FILE*) $SRC/gcc/lra.c:2590 0x9f9298 do_reload $SRC/gcc/ira.c:5465 0x9f9298 execute $SRC/gcc/ira.c:5649 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions.
Confirmed with a local build.
I am having quite a lot of trouble understanding what is going wrong, or maybe I should say, what parts are going right. I believe it tries to match the fifth alternative for anddi3_insn here which is: '&r' 'r' 'De' This fails because of the early clobber, rightfully so because: (insn 13 11 14 2 (set (reg:DI 0 r0 [125]) (and:DI (reg:DI 1 r1 [+-4 ]) (const_int 1 [0x1]))) "../t.c":3 79 {*anddi3_insn} (nil)) DI r0 overlaps with DI r1, seeing you need two consecutive GPRs to contain a DImode. I decided to debug reload to find out why it had picked r1 and I find 'get_hard_regno' first picks r2 for (subreg:DI (SI 122)) in the same instruction. If we go up we see: (insn 10 9 11 2 (set (reg:SI 2 r2 [122]) (xor:SI (reg:SI 0 r0 [orig:123 a ] [123]) (const_int 1 [0x1]))) "../t.c":3 111 {*arm_xorsi3} (nil)) Then in 'get_hard_regno' it invokes 'subreg_regno_offset', that returns 'nregs_xmode - nregs_ymode' as offset in big endian for paradoxical subregs with offset 0, where, xmode is inner and ymode is outer. That is '-1' in our case (and always negative). So I believe reload is now seeing 'r1-r2' as the register pair for that first 'and' operand and 'r0-r1' as the destination operand. At first I was thinking this was a middle-end issue, specifically for paradoxical subregs. However, I also saw a bit of Aarch64 big endian assembly that used 'odd' registers to represent DI register pairs (V2DI). Given the comment in 'subreg_regno_offset': /* If this is a big endian paradoxical subreg, which uses more actual hard registers than the original register, we must return a negative offset so that we find the proper highpart of the register. We assume that the ordering of registers within a multi-register value has a consistent endianness: if bytes and register words have different endianness, the hard registers that make up a multi-register value must be at least word-sized. */ It made me start to think that GCC expects register pairs in big endian to be "called" by their Least Significant Register (LSR) and to be counted back from there. So '[r1, r0]' to be called (DI r1). I am not entirely sure about this though... I tried changing the arm back-end to only accept DI mode register pairs if the register is odd. That fixed this case but broke a lot of other things. I am thinking another way to fix it is to adapt Arm's 's_register_operand' to not accept paradoxical subregs in big endian, but I would first like to understand how the middle end expects/sees/generates register pairs if 'REG_WORDS_BIG_ENDIAN' is true.
@Vlad: I added you to this ticket to see if maybe you can shine some light on how GCC's register allocator deals with register pairs in big endian, I am struggling to figure out how all of this works together, see comment before this. Thanks in advance!
This bug has been fixed in current trunk gcc sources. r265398 is the patch ID which is fixing this.
I can confirm the ICE no longer occurs, but I am not entirely convinced the issue was "fixed" by this. I fear the underlying fault is still there, it is simply hidden now.
I've found a simpler reproducer for the same crash, this one uses a NEON type, and affects little-endian as well as big-endian: // test.c #include <arm_neon.h> int32x2_t b(long c, ...) {} $ arm-none-eabi-gcc -march=armv7-a -c test.c -mfloat-abi=hard -mfpu=neon test.c: In function 'b': test.c:1:1: error: insn does not satisfy its constraints: 1 | __simd64_int32_t b(long c, ...) {} | ^~~~~~~~~~~~~~~~ (insn 6 11 9 2 (set (reg/i:V2SI 0 r0) (reg:V2SI 2 r2 [orig:110 <retval> ] [110])) "test.c":1:1 939 {*neon_movv2si} (nil)) during RTL pass: reload test.c:1:1: internal compiler error: in extract_constrain_insn, at recog.c:2206 0xbaf641 _fatal_insn(char const*, rtx_def const*, char const*, int, char const*) /tmp/dgboter/bbs/rhev-vm1--rhe6x86_64/buildbot/rhe6x86_64--arm-none-eabi/build/src/gcc/gcc/rtl-error.c:108 0xbaf672 _fatal_insn_not_found(rtx_def const*, char const*, int, char const*) /tmp/dgboter/bbs/rhev-vm1--rhe6x86_64/buildbot/rhe6x86_64--arm-none-eabi/build/src/gcc/gcc/rtl-error.c:119 0xb82846 extract_constrain_insn(rtx_insn*) /tmp/dgboter/bbs/rhev-vm1--rhe6x86_64/buildbot/rhe6x86_64--arm-none-eabi/build/src/gcc/gcc/recog.c:2206 0xa6fa52 check_rtl /tmp/dgboter/bbs/rhev-vm1--rhe6x86_64/buildbot/rhe6x86_64--arm-none-eabi/build/src/gcc/gcc/lra.c:2182 0xa74166 lra(_IO_FILE*) /tmp/dgboter/bbs/rhev-vm1--rhe6x86_64/buildbot/rhe6x86_64--arm-none-eabi/build/src/gcc/gcc/lra.c:2616 0xa2a224 do_reload /tmp/dgboter/bbs/rhev-vm1--rhe6x86_64/buildbot/rhe6x86_64--arm-none-eabi/build/src/gcc/gcc/ira.c:5469 0xa2a224 execute /tmp/dgboter/bbs/rhev-vm1--rhe6x86_64/buildbot/rhe6x86_64--arm-none-eabi/build/src/gcc/gcc/ira.c:5653 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions.
Hi, This one sort of fell through the cracks on me. With help from Vlad and Richard S. I managed to track the issue to uses_hard_regs_p and the way it handles paradoxical subregs (or fails to). I have a patch for this, which I will rebase and test. Ill give your new testcase a whirl Oliver thanks! Cheers, Andre
Oliver, Your new example doesn't seem to be hitting the same issue as the first one. The first failure was being caused by paradoxical subregs, the second one doesn't have paradoxical subregs. I'll try to investigate it.
I believe the PR is duplication of PR88850 (see my comments there). The cost of register movement in insn 6 is 2. LRA/reload does not check constraints for such cost and at the very LRA end (when there is a check for all insn constraints) the error is reported.
Hi Vlad, I don't think it is a duplication. I believe this PR is caused by an issue with 'uses_hard_regs_p' and paradoxical subregs. I proposed a patch in https://gcc.gnu.org/ml/gcc-patches/2019-01/msg00307.html , though it has a mistake, I forgot to add '|| SUBREG_P (x)' to the 'if (REG_P (x))' line since x can now be a subreg. I haven't had much time lately, but I am now running the last bootstrap, have done arm and aarch64, now doing x86. I can't reproduce this on GCC 9 but I can on 8 and earlier and the latent bug is still there on 9. So I believe we should fix it regardless. Once the bootstrap is done Ill post the fixed patch + testcase (really only useful for gcc-8) on the mailing list. Cheers, Andre
(In reply to avieira from comment #10) > Hi Vlad, > > I don't think it is a duplication. Sorry, I was not clear. My comment relates to test #include <arm_neon.h> int32x2_t b(long c, ...) {} $ arm-none-eabi-gcc -march=armv7-a -c test.c -mfloat-abi=hard -mfpu=neon test.c: In function 'b': test.c:1:1: error: insn does not satisfy its constraints: 1 | __simd64_int32_t b(long c, ...) {} | ^~~~~~~~~~~~~~~~ (insn 6 11 9 2 (set (reg/i:V2SI 0 r0) (reg:V2SI 2 r2 [orig:110 <retval> ] [110])) "test.c":1:1 939 {*neon_movv2si} (nil))
Author: avieira Date: Wed Feb 20 14:11:43 2019 New Revision: 269039 URL: https://gcc.gnu.org/viewcvs?rev=269039&root=gcc&view=rev Log: [GCC] PR target/86487: fix the way 'uses_hard_regs_p' handles paradoxical subregs gcc/ChangeLog: 2019-02-20 Andre Vieira <andre.simoesdiasvieira@arm.com> PR target/86487 * lra-constraints.c(uses_hard_regs_p): Fix handling of paradoxical SUBREGS. gcc/testsuite/ChangeLog: 2019-02-20 Andre Vieira <andre.simoesdiasvieira@arm.com> PR target/86487 * gcc.target/arm/pr86487.c: New. Added: trunk/gcc/testsuite/gcc.target/arm/pr86487.c Modified: trunk/gcc/ChangeLog trunk/gcc/lra-constraints.c trunk/gcc/testsuite/ChangeLog
Author: law Date: Fri Nov 1 22:37:04 2019 New Revision: 277729 URL: https://gcc.gnu.org/viewcvs?rev=277729&root=gcc&view=rev Log: Backport from trunk 2019-02-20 Andre Vieira <andre.simoesdiasvieira@arm.com> PR target/86487 * lra-constraints.c(uses_hard_regs_p): Fix handling of paradoxical SUBREGS. PR target/86487 * gcc.target/arm/pr86487.c: New. Added: branches/gcc-8-branch/gcc/testsuite/gcc.target/arm/pr86487.c Modified: branches/gcc-8-branch/gcc/ChangeLog branches/gcc-8-branch/gcc/lra-constraints.c branches/gcc-8-branch/gcc/testsuite/ChangeLog
The GCC 7 branch is being closed, re-targeting to GCC 8.4.
Jeff seems to have backported this to gcc-8 already, so I guess we can close this?
GCC 8.4.0 has been released, adjusting target milestone.
Closing as it has been backported to 8 and 7 is closed.