<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Too early validation of inline assembly constraints"
   href="https://bugs.llvm.org/show_bug.cgi?id=52171">52171</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Too early validation of inline assembly constraints
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>11.0
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>Other
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>other
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>C
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedclangbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>marian.buschsieweke@ovgu.de
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>blitzrakete@gmail.com, dgregor@apple.com, erik.pilkington@gmail.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Summary
-------

Compilation for AVR with the header avr/wdt.h included fails due to different
behavior regarding the validation of the constraints of operands for inline
assembly. The issue is observed with AVR, but I think it could apply equally to
all other architectures.

Background Information
----------------------

Accessing a memory mapped h/w register in AVR takes 1 CPU cycle if it is done
as I/O register (that is via a special instruction that takes the I/O register
address as immediate), or 2 CPU cycles if it is done via regular load/store
instructions to its memory address. The avrlibc has a macro _SFR_IO_REG_P()
that evaluates to a c expression which is true, if and only if the given
parameter is an IO register (so its address is in the range [0;63], allowing
its value to be used as immediate). The constraint "I" for operands in extended
inline assembly enforces that the operand is a value suitable as immediate,
allowing the single-cycle access with the I/O register load/store instructions. 

The AVR watchdog timer (WDT) allows changes of the configuration only after
writing a magic number into a magic register and only for a brief time window
of a few CPU cycles. For this reason changes of the WDT configuration are
implemented in inline assembly to ensure that the timing requirements are
fulfilled. I think (but I'm not 100% sure) that at least some AVR MCUs require
the use of the faster I/O register access to meet the timing requirements when
changing the WDT configuration.

The Issue
---------


The issue is best explained with a code snippet:

<span class="quote">> static __inline__
> __attribute__ ((__always_inline__))
> void wdt_enable (const uint8_t value)
> {
>       if (_SFR_IO_REG_P (_WD_CONTROL_REG))
>       {
>               __asm__ __volatile__ (
>                               [...]
>                               : /* no outputs */
>                               : "I" (_SFR_IO_ADDR(_WD_CONTROL_REG)),
>                               [...]
>                               : "r0"
>               );
>       }
>       else {
>               /* variant not using _WD_CONTROL_REG as immediate */
>               [...]       
>       }
> }</span >

Since _SFR_IO_REG_P() evaluates to a compile time constant expression that
yields true if the given address is suitable for inline assembly and false
otherwise, either the then or the else clause is known to be a dead branch. GCC
eliminates the dead branch before validation of the constraint I. So if `"I"
(_SFR_IO_ADDR(_WD_CONTROL_REG))` is an unfulfilled constrained, this is part of
a dead branch that is never checked in GCC. In clang the constraints are
validated before elimination of the dead branch, so compilation fails for MCUs
that do not support single cycle access to `_WD_CONTROL_REG`.

What to Do about This?
----------------------

First, is the behavior of clang here actually is incorrect? To me, enforcing
constraints of inline assembly operands of dead branches feels consistent with
what C compilers do: Invalid syntax at C level is also not tolerated even on
dead branches. To me, this feels like the avrlibc exploiting an implementation
detail of GCC and the issue should be fixed there. But I guess one could argue
that inline assembly GCC extension that doesn't have to be consistent with
regular C compiler behavior, and at least conceptually the enforcement of the
constraints belongs to the stage of invoking an assembler that is done after
the C level stage including optimization is done.

So what is the upstream opinion on this? Is this a valid bug, or should it be
fixed at avrlibc?

References
----------

See <a href="https://lists.gnu.org/archive/html/avr-libc-dev/2021-10/msg00000.html">https://lists.gnu.org/archive/html/avr-libc-dev/2021-10/msg00000.html</a> for
discussion on the avrlibc mailing list.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>