From: Philipp Tomsich <[email protected]>

synth_mult accepts a sub-algorithm of up to MAX_BITS_PER_WORD
operations from its recursive call and appends the current operation
at index ops before the too-long check discards the result. That
index is one past both arrays. The write to op[MAX_BITS_PER_WORD]
aliases log[0..3] and overwrites the shift counts of the algorithm
being built, and the write to log[MAX_BITS_PER_WORD] falls outside
the struct. The cache update just above the check reads op[] at the
same index.

AVR reaches this at -O1/-O2, where MAX_BITS_PER_WORD is 8 and a
SImode multiply by a dense constant needs more operations than that:

  uint32_t f (uint32_t x) { return x * 0xaaab; }

Size the arrays for the transient state.

        PR middle-end/127031

gcc/ChangeLog:

        * expmed.h (struct algorithm): Add one slot to the op and log
        arrays for the operation synth_mult appends to a full
        sub-algorithm before discarding it.

gcc/testsuite/ChangeLog:

        * gcc.target/avr/pr127031.c: New test.
---
 gcc/expmed.h                            | 9 ++++++---
 gcc/testsuite/gcc.target/avr/pr127031.c | 9 +++++++++
 2 files changed, 15 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/avr/pr127031.c

diff --git a/gcc/expmed.h b/gcc/expmed.h
index 78f3f36e6615..4a2c60e055e5 100644
--- a/gcc/expmed.h
+++ b/gcc/expmed.h
@@ -101,9 +101,12 @@ struct algorithm
      word size, but the worst-case algorithms will be if we have few
      consecutive ones or zeros, i.e., a multiplicand like 10101010101...
      In that case we will generate shift-by-2, add, shift-by-2, add,...,
-     in total wordsize operations.  */
-  enum alg_code op[MAX_BITS_PER_WORD];
-  char log[MAX_BITS_PER_WORD];
+     in total wordsize operations.  OPS never exceeds MAX_BITS_PER_WORD,
+     and the final entry is scratch: the algorithm search appends an
+     operation there before checking whether the sequence has grown too
+     long.  */
+  enum alg_code op[MAX_BITS_PER_WORD + 1];
+  char log[MAX_BITS_PER_WORD + 1];
 };
 
 /* The entry for our multiplication cache/hash table.  */
diff --git a/gcc/testsuite/gcc.target/avr/pr127031.c 
b/gcc/testsuite/gcc.target/avr/pr127031.c
new file mode 100644
index 000000000000..12d978af17eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr127031.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef __UINT32_TYPE__ uint32_t;
+
+uint32_t f (uint32_t x)
+{
+  return x * 0xaaab;
+}
-- 
2.55.0

Reply via email to