Description
clang version: 16.0.0
compiler flags: -std=c2x -O2
Observed behavior
Given the following code:
unsigned char f(unsigned _BitInt(4)* ptr) {
return *ptr;
}
unsigned char g(_BitInt(4)* ptr) {
unsigned _BitInt(4) uint = *ptr;
return uint;
}
The generated code for f
and g
does not mask out "unused" bits from *ptr
:
f: # @f
movzx eax, byte ptr [rdi]
ret
g: # @g
movzx eax, byte ptr [rdi]
ret
https://godbolt.org/z/Ev8sbhb84
Expected behavior
The x86-64 psABI specifies that the unused bits within an object of _BitInt(N)
type can take unspecified values:
The value of the unused bits beyond the width of the
_BitInt(N)
value but within the size of the_BitInt(N)
are unspecified when stored in memory or register.
This means that *ptr
in both cases can have the object representation 0b00010000
, representing the signed/unsigned _BitInt(N)
value 0
. But according to the generated code this object representation is passed as-is to the returned unsigned char in both cases, which translates to the return value 16
.
As 0b00010000
is a valid object representation for representing the value 0
here, I would expect both functions to return 0
in this case.
In general this requires masking out the unused bits.
Notes
It looks like the current implementation assumes that valid object representations have all zeroes for the unused bits, and other representations are trap representations.