<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/59306>59306</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[Clang (all versions][x86-64 backend] Incorrect handling of uint64_t bitfields
</td>
</tr>
<tr>
<th>Labels</th>
<td>
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
g0blue
</td>
</tr>
</table>
<pre>
# Overview
**TL;DR:** See godbolt link: https://godbolt.org/z/GhWdrnv5s
# Details
There seems to be an "optimization" for bitfield members that are <= 32bits but have a 64-bit data type. Specifically, reading the value returns a signed int32, not an unsigned int64. Most of the time this does not cause a problem, but when shifting the bitfield value directly the result can meet or exceed 32 bits and the result is incorrect.
## Reproduction
Compile and run the below Example Code
## Example Code
```cpp
#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>
static constexpr uint32_t NUM_BITS = 27;
struct foo
{
foo() { Fields.data = 0;}
union Fields
{
struct Bits
{
uint64_t FlagValue : 1;
uint64_t Reserved_0 : 5;
uint64_t Value : NUM_BITS;
} Bits;
uint64_t data;
} Fields;
enum VALUE
{
VALUE_BIT_SHIFT = 6,
};
void SetValue( const uint64_t value )
{
Fields.Bits.Value = value >> VALUE_BIT_SHIFT;
}
// MSVC will note that GetValue and GetValue2 are identical and the
// linker will remove GetValue and make both calls from main() call
// GetValue2. All versions of MSVC work correctly.
//
// All versions of clang fail
// GCC versions >= 10.1 fail (older versions work correctly)
uint64_t GetValue( void ) const
{
// This function may return INCORRECT results when:
// (32 - VALUE_BIT_SHIFT) <= NUM_BITS <= 32!!
//
// In these error cases a 32-bit register is left shifted
// and x86-64 HW will sign extend the result.
// So, we could lose MSBs, or we could incorrectly get a sign-extended result
//
// For Clang - it's even in the IR!!
// %8 = trunc i64 %7 to i32, !dbg !144
// %9 = shl i32 %8, 6, !dbg !146
// %10 = sext i32 %9 to i64, !dbg !147
return (Fields.Bits.Value << VALUE_BIT_SHIFT);
}
uint64_t GetValue2( void ) const
{
// This version correctly left shifts a 64-bit register
return (static_cast<uint64_t>(Fields.Bits.Value) << VALUE_BIT_SHIFT);
}
};
int main()
{
foo f;
uint64_t start = ((uint64_t(3) << (NUM_BITS-2)) - 1) << foo::VALUE_BIT_SHIFT;
f.SetValue(start);
uint64_t val = f.GetValue();
uint64_t val2 = f.GetValue2();
printf("Start: 0x%" PRIx64 "\n", start);
printf("Get: 0x%" PRIx64 "\n", val);
printf("Get2: 0x%" PRIx64 "\n", val2);
printf("%s", (val == val2 && val == start) ? "Correct Results" : "Bug detected!!");
return int(val != val2 || val != start);
}
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJyMV91y4rgSfhpx0wVly_yYCy6CCbOp2tk9FbKzlynZboPOyBIlySTZpz8l2cY2mNlDuUKQuj_179cyM4YfJeKGLLZksZuwyp6U3hyDVFQ4SVX-tSE0gj8vqC8cP0iwI8FT85e65-13Em13ryRqfsMBEY4qT5WwILj8SaInOFl7Nl5kT-i-2Z0pfSR0_w-h-2-nv3MtLwszxI9gh5ZxMVh-O6FGMIilAasgRWASCKXqbHnJ_2GWK0kohUJpSLktOIocSixT1AbsiVlgGoFECYl2ENGUWwNpZeHELggMlvNpyi3kzDKwX2ecARzOmPGCZ0yIL0IT0MhyLo9gTwgXJioEjbbS0gADH80cuLQRdbJSWWdfJbuN5XwG8F0ZC6rwGJaXCPbEDeQKjVfJWGWcNWetUoGlQ3I2fpxQgjnxwrbnXz2sDcm5xsyKL7-n0VTCYUkoES0oDfiZIeYQUfB-M5n3JbkBLjOlHcbsJhUuG6941iqvMh_i3naiyjMX6OF0JWvDUKgPeP5k5VkgJCrHEcCH28ugfrLz-arAZSaq3KfO2JxLOzuR6PnRtnq4y6V1iTV9Af_XWGZ5BpmSxuLnWUPl0_hu4Y-_vr9vX94O4GqGrki0HerpKrNQKNWsrpptAPCrNCZ0DWS1hb3LlZn56nJYgYNa7TrxSnIlG7FudYDoPs2RW25bqTsRj-bL7d3C7Wcv2PGHrxj_cT0aXr16rPaKBvUF8_fgqrbo1MYO7h3SarTB7EVxTVa72plhZO_gXOAGBzrFJlr3qiirEn48_f7X81go_Yaz5P3w28v-DXxCloQmA_QR2IviORzQet8IjeuK6YysW5HQ9S8S2BSC83lWx8id3mhGzyR6vrWvc_taMD18T6zw_fAjgQ8uhCMRrNnuW2Oo7872B_UkyHOU1vFaSwR3gI7AUdeQGkt1wSFeyX4ipMqewLGjgUKrEkrGZVPzbvUO9GrEDJ6EgAtqw5U0jg5rB5T-CQ0Nia_ZrX4bhRrsFiETTB6hYHzk3CTpRH2QdxAGs9BLA6GxEjnqTmRoxyCf11x_65WBrwvvta-Hsew3lrw5si8q6ZkUSvbVTBB4-SP58_X1OXlrKNl4yneTc1A9DQyhcURhelcpjmzq-dYjrmbeERq6ZwRu9IgXz-YGAbVWGjJm0I25iPopqfHIjUXtJofAwtazCfNRKFcvn_FyupzDb3_XJeWGIuCnxcEcmo2qH5Sbgh8ImapEDkIZhO-HrXGrSncb1wkmvuCItpnJ0_oUzJsz_u8A7JWGxNfUFLgldGUALyiB12Pu5fVxQP0_i9h3ttWVzIAv525p5S4uvL4gEBrm6dF9hfP5Y5S1RzEn4fQ8rFNe3iIsHyOEQQ2Bn7bFWHs7lvNblNUQpalNQuMx1kpIlIxU4C1L3zLWXQfRxy10x579NmratWvUXiWa7kLXlmoD1PlUT_33jBlLoqQ1y9HDiL_X1vq1y52_dwOES9sjyPELAxSD6F1DZSzT1mfRa8dXY2kc9SwjNG77fkrdIXQNUwh7Eu5SEj2R6OnhjClmvQHnz73Nqc_DvY0XJryFxaxHjQPdvii9kaU3wt0BZ82lLfw2PXh7oicIPglduMv-f15fPn1vUbJI3PXflfSo2X2cb-hR4F9wLkwMUG4gqMf4Vwj6K0sIXZhGlNC4iWFzI3CtuiR0Cb3l1jUgkRsDNKmL313Q3NRwdjirCKXb6gg5WswcLddURelIiJuG4NK2BtCwM2CVkFUCveW72HYl397dJ_kmytfRmk1wEy5XQRDMV-t4ctrM8_WaFutVuorjNYspwyAMsiDIgrTIY8YmfEMDSkMa0DAOozCeBcVivqTFOmR0hTQsyDzAknExE-JSuvfICTemws1iHQXLiWApCtO-0eqNE5qm1dGQeSC4saZTs9wK_-5bUzyhMevdJ8hiRxbbZmalLPuJMieLHby0IwZOTObCvYupoqvr9p3MTCotNjfvvtyeqnSWqZLQvTOj-ZqetfovZpbQvXfFELr33vwvAAD__2CQY04">