Bug 86487 - [8 Regression] insn does not satisfy its constraints on arm big-endian
Summary: [8 Regression] insn does not satisfy its constraints on arm big-endian
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 7.3.1
: P2 normal
Target Milestone: 8.5
Assignee: Not yet assigned to anyone
URL:
Keywords: ice-on-valid-code
Depends on:
Blocks:
 
Reported: 2018-07-11 11:00 UTC by ktkachov
Modified: 2021-02-22 10:20 UTC (History)
2 users (show)

See Also:
Host:
Target: arm
Build:
Known to work: 6.4.1
Known to fail: 7.3.1, 8.1.1, 9.0
Last reconfirmed: 2018-07-16 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description ktkachov 2018-07-11 11:00:40 UTC
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.
Comment 1 avieira 2018-07-16 08:47:31 UTC
Confirmed with a local build.
Comment 2 avieira 2018-07-26 10:18:51 UTC
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.
Comment 3 avieira 2018-07-26 10:21:59 UTC
@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!
Comment 4 Navya 2018-11-05 10:59:56 UTC
This bug has been fixed in current trunk gcc sources. 
r265398 is the patch ID which is fixing this.
Comment 5 avieira 2018-11-16 10:33:09 UTC
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.
Comment 6 Oliver Stannard 2018-12-19 10:37:46 UTC
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.
Comment 7 avieira 2018-12-19 14:15:36 UTC
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
Comment 8 avieira 2018-12-19 15:45:43 UTC
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.
Comment 9 Vladimir Makarov 2019-01-31 15:34:57 UTC
  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.
Comment 10 avieira 2019-01-31 15:44:59 UTC
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
Comment 11 Vladimir Makarov 2019-01-31 22:05:29 UTC
(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))
Comment 12 avieira 2019-02-20 14:12:15 UTC
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
Comment 13 Jeffrey A. Law 2019-11-01 22:37:35 UTC
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
Comment 14 Richard Biener 2019-11-14 07:50:33 UTC
The GCC 7 branch is being closed, re-targeting to GCC 8.4.
Comment 15 avieira 2020-01-27 10:35:50 UTC
Jeff seems to have backported this to gcc-8 already, so I guess we can close this?
Comment 16 Jakub Jelinek 2020-03-04 09:32:34 UTC
GCC 8.4.0 has been released, adjusting target milestone.
Comment 17 avieira 2021-02-22 10:19:32 UTC
Closing as it has been backported to 8 and 7 is closed.