[llvm] [AVR] Adapt getPostIndexedAddressParts() and getPreIndexedAddressParts (PR #145040)

Tom Vijlbrief via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 20 06:59:16 PDT 2025


https://github.com/tomtor created https://github.com/llvm/llvm-project/pull/145040

Fixes https://github.com/llvm/llvm-project/issues/143247

For testing this PR I used the following code:

```
#if 1
#define PA      0x1 // Bad
#else
#define PA      0x2 // Good
#endif

volatile char *const PORT = (char *const) PA;

extern void nil(short);

void bug()
{
  short s= 0;
 
  while (1) {
    s++;
    *PORT = *PORT | 0x80;
    nil((s & 0xF) + PA);
  }
}

unsigned
demo_post (unsigned short value, unsigned short *buffer, unsigned short *bufend)
{
  unsigned short *tmp;

  for (tmp = buffer; tmp < bufend; tmp++)
    value -= *tmp;

  return value;
}

const char *
demo_2 (const char *in, char *out)
{
  while (1)
    {
      if (*in == 'a')
        {
          const char *p = in + 1;
          while (*p == 'x')
            ++p;
          if (*p == 'b')
            return p;
          while (in < p)
            *out++ = *in++;
        }
    }
}
```

It contains the code which triggers the original bug and two demo functions which still emit post/pre-index code triggered by `getPreIndexedAddressParts`.

When comparing the generated assembly the only difference is in the generated code for `bug()`

```
16,17c16,17
<       ldi     r24, 0
<       ldi     r25, 0
---
>       ldi     r26, 0
>       ldi     r27, 0
20,25c20,26
<       sbi     1, 7
<       adiw    r24, 1
<       movw    r16, r24
<       andi    r24, 15
<       andi    r25, 0
<       adiw    r24, 1
---
>       ld      r24, X+
>       ori     r24, -128
>       movw    r16, r26
>       andi    r26, 15
>       andi    r27, 0
>       st      X+, r24
>       movw    r24, r26
27c28
<       movw    r24, r16
---
>       movw    r26, r16
```

For future reference, I examined tests from the gcc torture collection, and determined that only the few following tests (from 1930 tests) generate pre/post index code:

```
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/20000412-6.c
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/20011126-2.c
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/980205.c
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/990524-1.c
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/pr20601-1.c
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/pr38051.c
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/pr44852.c
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/pr44942.c
#$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/pr67037.c
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/stdarg-2.c
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/stdarg-3.c
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/va-arg-22.c
$C -O2 -target avr-none $M -S gcc/gcc/testsuite/gcc.c-torture/execute/va-arg-26.c
```

The commented out test crashes clang, as do many others.

So for some reason, the AVR pre/post index only is generated in a few cases, less then I would expect, but that is not related to this PR.

The reason why this PR is effective for the specific `bug()` code generation is not clear to me.

The fix can be suboptimal, but it only removes a certain case of optimization which is incorrect for the `bug()` code, so there is minimal danger of an regression. I would really appreciate any feedback from experienced LLVM contributors about the root cause or alternative ways to handle the issue.



>From a9df1888755677f3b5cba65bc34927aace073c5f Mon Sep 17 00:00:00 2001
From: Tom Vijlbrief <tvijlbrief at gmail.com>
Date: Tue, 17 Jun 2025 15:11:51 +0200
Subject: [PATCH] [AVR] Adapt getPostIndexedAddressParts() and
 getPreIndexedAddressParts

Fixes https://github.com/llvm/llvm-project/issues/143247
---
 llvm/lib/Target/AVR/AVRISelLowering.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp
index 9747ad0c5cd58..00e1fb8fd5528 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp
@@ -1052,6 +1052,10 @@ bool AVRTargetLowering::getPreIndexedAddressParts(SDNode *N, SDValue &Base,
       return false;
     }
 
+    // Fixes https://github.com/llvm/llvm-project/issues/143247
+    if (Op->getOperand(0)->hasOneUse())
+      return false;
+
     Base = Op->getOperand(0);
     Offset = DAG.getSignedConstant(RHSC, DL, MVT::i8);
     AM = ISD::PRE_DEC;
@@ -1114,6 +1118,10 @@ bool AVRTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
       if (AVR::isProgramMemoryAccess(LD))
         return false;
 
+    // Fixes https://github.com/llvm/llvm-project/issues/143247
+    if (Op->getOperand(0)->hasOneUse())
+      return false;
+
     Base = Op->getOperand(0);
     Offset = DAG.getConstant(RHSC, DL, MVT::i8);
     AM = ISD::POST_INC;



More information about the llvm-commits mailing list