<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/136603>136603</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Loop unrolling confuses __builtin_dynamic_object_size() and __builtin_constant_p()
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          kees
      </td>
    </tr>
</table>

<pre>
    This is from https://github.com/ClangBuiltLinux/linux/issues/2076 where commit 2d1e8a03f5eeff48cd7928d003fc12f728b2c7cf seems to have exposed some recent Linux kernel code to the loop unroller (though oddly only on ARM). Attempting to extract a minimal reproducer has been a challenge, but it appears that something about loop unrolling confuses `__builtin_constant_p()`. Loop variables assigned from `__builtin_dynamic_object_size()` appear constant, whereas if it is left in a macro, they correctly stay dynamic.

It seems that a `noreturn` branch is also be required to trigger this. Anything that disables the loop unrolling fixes the problem (via `#pragma` or via changes in loop size via `NUM_ADDRS`). Bringing the external loop constraint explicitly down into the inner loop (`j < NUM_ADDRS`) also fixes it.

I'm not sure what to do next to narrow this down further.

```c
// clang -Wall -O2 -c repro.c -o repro.o
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define __compiletime_warning(msg) __attribute__((__warning__(msg)))
#define __noreturn __attribute__((__noreturn__))

extern void variable_calc_constant(size_t) __compiletime_warning("variable calculation is constant");
extern void macro_calc_constant(size_t) __compiletime_warning("macro calculation is constant");
extern void freakout(void) __noreturn;
extern int check(int);

extern int unknown;

// must be less than 10 (loop unrolling limit?)
#define NUM_ADDRS 4

struct inner {
        unsigned char addr[2]; // must be greater than 1 to show warnings in unroll
};

struct middle {
        struct inner bytes;
};

struct outer {
        struct middle array[NUM_ADDRS];
};

void repro(void) {
        struct outer *outer;
        struct middle *middle;
        int i, c;

        outer = malloc(sizeof(*outer));
        middle = outer->array;
        for (i = 0, c = 0; i < unknown && c < NUM_ADDRS; i++) {
                struct inner addr = { };
                int j;

                if (check(i))
 continue;

//#pragma clang loop unroll(disable)
 for (j = 0; j < c /*&& j < NUM_ADDRS*/; j++) {
 const size_t v_size = __builtin_dynamic_object_size(&middle[j].bytes, 0);
 #define      m_size __builtin_dynamic_object_size(&middle[j].bytes, 0)

 if (__builtin_constant_p(v_size))
 variable_calc_constant(v_size);
                        if (__builtin_constant_p(m_size))
 macro_calc_constant(m_size);

                        if (m_size < sizeof(addr))
                                freakout();

 if (__builtin_memcmp(&middle[j].bytes, &addr, sizeof(addr)) == 0)
 break;
                }
                if (j == c)
                        c++;
        }
}
```

Produces (on x86_64 host, FWIW):

```
$ clang -Wall -O2 -c repro.c -o repro.o
repro.c:53:5: warning: call to 'variable_calc_constant' declared with 'warning' attribute: buggy: variable calculation is constant [-Wattribute-warning]
   53 | variable_calc_constant();
      | ^
repro.c:53:5: warning: call to 'variable_calc_constant' declared with 'warning' attribute: buggy: variable calculation is constant [-Wattribute-warning]
repro.c:53:5: warning: call to 'variable_calc_constant' declared with 'warning' attribute: buggy: variable calculation is constant [-Wattribute-warning]
repro.c:53:5: warning: call to 'variable_calc_constant' declared with 'warning' attribute: buggy: variable calculation is constant [-Wattribute-warning]
repro.c:53:5: warning: call to 'variable_calc_constant' declared with 'warning' attribute: buggy: variable calculation is constant [-Wattribute-warning]
5 warnings generated.
```

Without loop unrolling, this does not emit warnings. The macro-based uses of `__builtin_dynamic_object_size()` aren't resolved (which itself seems to be a bug), but the variable based ones are. Specifically, when `__builtin_dynamic_object_size()` is being determined at compile time as part of the loop unrolling, it _cannot_ reach 0 -- the loop unroller is exceeding the maximum loop counter and producing a iteration beyond the bounds of the array. This can be seen in the _fifth_ (impossible) call in the binary output:

```
        xor     edi, edi
        call variable_calc_constant@PLT
```

https://godbolt.org/z/eT5KdTxbv
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsWE1v4zjS_jXMpWBDoSzbOfhgJx1g8Pa8O5jpRR8FiixZTFOkl6SSeH79oijaiR27e3r3tMAEhq2Ixecp1heLFCHorUVcsWrDqocbMcTO-dU3xHDTOLVffel0AB2g9a6HLsZdYOWa8UfGH7c6dkMzla5n_PHeCLvdDNrEz9oOr4w_mvyrQxgwMP7Ii8UcXjr0CNL1vY7A1S0uRVG2FWLbzpZSLe74UhVF2cpb3i74suFyIVsIiH2A6KATzwj4unMBFQTXI3iUaCMkVviG3qIB6RSSdOwQjHM7GKx3xqAHxpexc8O2A6eU2YOz6QvWv__K-N0U1jFiv4vabmk-vkYvZAQBvba6FwY87rxTg0QPnQjQIFoQIDthDNotMn4PzRBBRxC7HQofIHYiJk1jR6iicUN8rxS9lM62Q8AAbF7UdUNW1LaWzoYobKx3jC8Zv2PzYgqfaeaz8Fo0BgNk_6nRPyfT1d6KXsvaNU8oYx30n3jEydrBgYL0Tp4RAXRL6usABtsImtbXC-kdycQO9yCd9yij2UOIYg-ZZ8qKNSvWv8SDs2jdglSyzmMcvCXexgsrO0IXJjhoyH__GrRHlfzl9XaLHmKnwxTWdj_aLEEpHcYlnzmVBFr9mgd23jUGe_Lzs07sjJc7L7a9IHrngV7LTtgtBlpcQiLbQJb__3_-Wq8fHn7_I829m8LGa7sd1aDQi-itMOO8ZD4vtI0Uk0ZLTVZR7sWCtjn-tLXoR3Ey_7x4AlbewxnNaI5xHToebMn4ogfrIoTBI7yQGaID5cDia3q0wnv3kuw10raDjx36DEDY6SPpn5S0IClRYfJVGAOTf3CYyDGopxImLj-6JF5qK82gkPQNUWk37Vj56dKQ0c3VMW3jtTEy7HEsDStstUWoa-n6nTYYdY_1i_BW2y3jyz5syVZ1LWL0uhki1nWK6WV9kEovRrn8OQU-BONlkMMovTlMLtaj0-HZaXVMvVoKI-u3_FlSDNVxVO-y9ozzw2yg2YMRUTtLyfCGw4m13JyxpgT8zyjT1J_laz2Kb24gEvp_pDjm8Xtxin3ZofzG-FITYEY7lRjsN-te7HEox2I_hEg1wGBIBcPCbUFZcpbeRvc6svLx3JvHHILZCBuiH2TMKccWRAb5b7C5UMpOeBBKeVZtOKseWLmBM3W2HkVMZYg0ojwLnXuBbNZUNkbliHXxcFxVpu-1UgbP-E9Ua_YRQ572cb4b4gf1T6GF92LPqs1bEakePsIlT6aEfufGi7CZka_TwwhwmZnx9fh0KkQ-1rRByCP7YShjlw_QC2OczHHr2hSemXFMthPIA2H5MEJMWPlpXPeJWOvSpq6TYJFUyI_lBnQqtTn4gPE54_M0_r7-khzjm_Q5t89F71HwJA622MDR4OdTyCRPH6xxHG1J62PiHKsNZWbUdsCzVDnuYrl-v8sQxpd5b8wQ2SRPb3YYtxw5xvk62-F8H-KJiqQ_WCOVCxjLDTynViKB_7jZmOdoqTZPrHqYjoHP78lTB3-_5fPo9xH-v4QejT5a-UpH9ZyhDpa_WtnfBC86-tSlV8j6M7LLBb0_ZfohWX9wxT0ccyqVtiPPD_7e1fkT1vO19NjLfvddszM-H6kv6kLhkjM06dUQ8WV7UkZdS5inA478_vpkDuETghE4fx86o3HBv41NfSAOZ-F1Oa_nM-hcSJ3x49dfvibzrM_aqpSes7_cUuWXrFxXJX2xcn3YVOhR0vzogPHFtVhcgEJpBLXLLzp2JHrc7BdwbGgIrRm22z09_KjnAFZtJl-PcycHwCq7oSqBLe6vp8dZYpAsqz79by73b5X_VvmiytVb97dFi15EVNOPdeSrjt3H8_14ck5HNAzpPIe9jkfEKXzpcNwRJo0IqCDdBbj2Z87zHi3jiwgegzPPqKiSvXSaztoxoHl3hdIgCLJKKszjdQWdU4_mGVVwFgOhTuGPHUrdavLKPt8T2J_QTAdokLp4hRF9r6kHFxHyeQXowAIiwE74SEv-eLonTh2hlsJaF2vwKGQHBUwmF-53dAB8lYjqcGDvxavuh_5wXh8sdaPCKhjvcdKVDOhIHqV4aHDvrEozGzdYFQ46pdaTPEURI0iQLEqnmzRct7qNXZ1a0X7nQtBjPzYGcxZqtBV-T-3sbogXd5PDVvXqfPpFlbpq-nkbTJBXMmNW_Pb5y8e4PLu4c6pxJk6d3zL--Cfjj_il-j_15bV5vlGrUt2Vd-IGV7eLWcXni2Ixu-lW1byVt82tVPOSiwUvq6ZYNpKLYrFUcr6Y3-gVL3hVzPgtL_isnE2xuluqBmfVrWrbO75kswJ7oc3UmOeeuG_SzeDqtpzPi_LGiAZNSPeQnFt8gTRKB9Tq4cavaNKkGbaBzQqjQwxvMFFHg6vPV67U_kKYpni4fu92M3iz-s7VJymSfyY77wj8_bVnXt_ziv87AAD__x2UzUI">