On 1/15/24 11:21, Laszlo Ersek wrote:

> - please only ever apply the bit-neg operator on values that are UINT32,
>   UINTN, or UINT64. Otherwise we get sign bit flipping, and that's
>   terrible. (Most people are not even aware of it happening.)

Doing this is BTW not as obvious as it might seem, at first sight. It's
good to remember some points about integer constants:

- assuming a naked constant (no 0x or 0 prefix, and no suffix such as l,
or u), the types considered are int, long, long long, in this order, by
the compiler, for the value (whichever fits first). That is: a "naked"
integer constant will *always* be signed.

- assuming an octal or hex prefix (0 or 0x), the candidate type list is
only *extended*; in other words, these prefixes don't *force* the type
to be unsigned, only *permit* it. The list becomes int, unsigned, long,
unsigned long, long long, unsigned long long. This is why 0x7F is just
"int", for example. However, 0x8000_0000 is not "int" anymore, but
"unsigned" (the value doesn't fit in "int", and the 0x prefix "permits"
"unsigned int").

- The suffixes do restrict the candidate type list. The "u" (and U)
suffixes remove the signed types, and add in the unsigned types. The
list becomes unsigned, unsigned long, unsigned long long. Furthermore,
the "l" and "ll" suffixes force (restrict) the type selection along a
different axis: they set the minimum integer "conversion rank", so to
say. The head of the list is trimmed so that the first candidate have
the specified rank. So with just an "l" suffix, the normal candidate
type list "int, long, long long" gets trimmed to "long, long long".
Assuming an "u" suffix in place already, adding the "l" suffix trims the
candidate type list "unsigned, unsigned long, unsigned long long" to
"unsigned long, unsigned long long". Assuming a 0x prefix and no "u"
suffix to begin with, appending the "l" suffix trims the type list "int,
unsigned, long, unsigned long, long long, unsigned long long" to "long,
unsigned long, long long, unsigned long long".

The "shorthand" to remember is: "prefixes permit, suffixes force".

Why I'm posting this wall of text: if we have a macro
BOUNDARY_OF_32_WORDS #defined as 0x7F, or a macro BIT1 #defined as
0x00000002, those are *signed int* values. And applying the bit-neg
operator ~ to them directly will flip the sign bit, and the resultant
value will be *implementation-dependent*. Given that we use two's
complement representation, the resultant value will always be signed int
with a negative value. (In a sign-and-magnitude representation e.g.,
where there is +0 and -0, we'd have to think further.) And then, for
example in:

  Offset & ~BOUNDARY_OF_32_WORDS

the negative value of the RHS is converted to the (unsigned) type of the
LHS [*], due to the default arithmetic conversions that are specified
for the & operator (too). This is done with the usual modular addition /
reduction.

So, when most people think that the above expression is simple
bit-fiddling, there are actually *two steps* that they miss: first, the
creation of a negative value of type "signed int" (using two's
complement representation), and then the reduction of that negative
"signed int" value to the (possibly wider) unsigned value range that the
other type is capable of representing [*].

[*] I'm taking some shortcuts here. The actual result type of the usual
arithmetic conversions (the "common real type for the operands
and result") is more complicated, but I won't describe all that here. It
can be read in the C std (drafts).

This is why I insist on one of two things in all such cases:

- either writing the expression as

    Offset & ~(UINTN)BOUNDARY_OF_32_WORDS

  where UINTN is supposed to match the type of Offset precisely,

- or #defining BOUNDARY_OF_32_WORDS already as an unsigned type --
either with an explicit cast ((UINTN)0x7F), or with a suitable suffix
(0x7Fllu).

Laszlo



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113820): https://edk2.groups.io/g/devel/message/113820
Mute This Topic: https://groups.io/mt/103680930/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: 
https://edk2.groups.io/g/devel/leave/9847357/21656/1706620634/xyzzy 
[arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to