diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2025-06-14 19:57:18 +0200 |
---|---|---|
committer | Georg-Johann Lay <avr@gjlay.de> | 2025-06-14 19:59:03 +0200 |
commit | 61789b5abec3079d02ee9eaa7468015ab1f6f701 (patch) | |
tree | 27d4bc549f45d2dfb0a24d134525ab5f1090ab80 | |
parent | 6923d412e61f447e423f2765b17500cc01a83c30 (diff) | |
download | gcc-61789b5abec3079d02ee9eaa7468015ab1f6f701.zip gcc-61789b5abec3079d02ee9eaa7468015ab1f6f701.tar.gz gcc-61789b5abec3079d02ee9eaa7468015ab1f6f701.tar.bz2 |
AVR: Fix PR120423 / PR116389.
The problem with PR120423 and PR116389 is that reload might assign an invalid
hard register to a paradoxical subreg. For example with the test case from
the PR, it assigns (REG:QI 31) to the inner of (subreg:HI (QI) 0) which is
valid, but the subreg will be turned into (REG:HI 31) which is invalid
and triggers an ICE in postreload.
The problem only occurs with the old reload pass.
The patch maps the paradoxical subregs to a zero-extends which will be
allocated correctly. For the 120423 testcases, the code is the same like
with -mlra (which doesn't implement the fix), so the patch doesn't even
introduce a performance penalty.
The patch is only needed for v15: v14 is not affected, and in v16 reload
will be removed.
PR rtl-optimization/120423
PR rtl-optimization/116389
gcc/
* config/avr/avr.md [-mno-lra]: Add pre-reload split to transform
(left shift of) a paradoxical subreg to a (left shift of) zero-extend.
gcc/testsuite/
* gcc.target/avr/torture/pr120423-1.c: New test.
* gcc.target/avr/torture/pr120423-2.c: New test.
* gcc.target/avr/torture/pr120423-116389.c: New test.
-rw-r--r-- | gcc/config/avr/avr.md | 35 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/avr/torture/pr120423-1.c | 29 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/avr/torture/pr120423-116389.c | 22 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/avr/torture/pr120423-2.c | 30 |
4 files changed, 116 insertions, 0 deletions
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 01b8e4b..f8bbdc7 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -5273,6 +5273,41 @@ ;;<< << << << << << << << << << << << << << << << << << << << << << << << << << ;; arithmetic shift left +;; Work around PR120423: Transform left shift of a paradoxical subreg +;; into left shift of the zero-extended entity. +(define_split ; PR120423 + [(set (match_operand:HISI 0 "register_operand") + (ashift:HISI (subreg:HISI (match_operand:QIPSI 1 "nonimmediate_operand") + 0) + (match_operand:QI 2 "const_int_operand")))] + "!reload_completed + && !avropt_lra_p + && <HISI:SIZE> > <QIPSI:SIZE>" + [(set (match_dup 4) + (zero_extend:HISI (match_dup 5))) + (set (match_dup 0) + (ashift:HISI (match_dup 4) + (match_dup 2)))] + { + operands[4] = gen_reg_rtx (<HISI:MODE>mode); + operands[5] = force_reg (<QIPSI:MODE>mode, operands[1]); + }) + +;; Similar happens for PR116389. +(define_split ; PR116389 + [(set (match_operand:HISI 0 "register_operand") + (subreg:HISI (match_operand:QIPSI 1 "nonimmediate_operand") + 0))] + "!reload_completed + && !avropt_lra_p + && <HISI:SIZE> > <QIPSI:SIZE>" + [(set (match_dup 0) + (zero_extend:HISI (match_dup 2)))] + { + operands[2] = force_reg (<QIPSI:MODE>mode, operands[1]); + }) + + ;; "ashlqi3" ;; "ashlqq3" "ashluqq3" (define_expand "ashl<mode>3" diff --git a/gcc/testsuite/gcc.target/avr/torture/pr120423-1.c b/gcc/testsuite/gcc.target/avr/torture/pr120423-1.c new file mode 100644 index 0000000..91b4bbc --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/pr120423-1.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ + +struct data +{ + int a; + int b; + long c; +}; + +unsigned char val; +unsigned val2; + +void func1 (struct data *d) +{ + d->a = 0; + d->b = 0x100 * val - 1; +} + +void func2 (struct data *d) +{ + d->a = 0; + d->c = 0x10000 * val2 - 1; +} + +void func3 (struct data *d) +{ + d->a = 0; + d->c = 0x1000000 * val - 1; +} diff --git a/gcc/testsuite/gcc.target/avr/torture/pr120423-116389.c b/gcc/testsuite/gcc.target/avr/torture/pr120423-116389.c new file mode 100644 index 0000000..928c135 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/pr120423-116389.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ + +struct T { int val; }; + +void f_int (int); +char* get_pos (void); +struct T* get_pT (void); + +void func (char i) +{ + struct T t = * get_pT (); + unsigned diff = get_pos () - &i; + + if (diff) + { + long val32 = t.val; + if (get_pos ()) + val32 = diff; + if (get_pos ()) + f_int (2 * val32); + } +} diff --git a/gcc/testsuite/gcc.target/avr/torture/pr120423-2.c b/gcc/testsuite/gcc.target/avr/torture/pr120423-2.c new file mode 100644 index 0000000..56e6141 --- /dev/null +++ b/gcc/testsuite/gcc.target/avr/torture/pr120423-2.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-ffixed-18 -ffixed-20 -ffixed-22" } */ + +struct data +{ + int a; + int b; + long c; +}; + +unsigned char val; +unsigned val2; + +void func1 (struct data *d) +{ + d->a = 0; + d->b = 0x100 * val - 1; +} + +void func2 (struct data *d) +{ + d->a = 0; + d->c = 0x10000 * val2 - 1; +} + +void func3 (struct data *d) +{ + d->a = 0; + d->c = 0x1000000 * val - 1; +} |